Skip to content

Commit acb677b

Browse files
authored
added typescript sample with all hooks (#204)
1 parent 32b3a2c commit acb677b

24 files changed

+935
-7
lines changed

lerna.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"packages": ["packages/*", "samples/*"],
2+
"packages": ["packages/*", "samples/*", "toolkits/*"],
33
"npmClient": "yarn",
44
"useWorkspaces": true,
55
"version": "independent"

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
]
1414
},
1515
"scripts": {
16-
"start": "cd packages/react-aad-msal && yarn start",
17-
"lint": "cd packages/react-aad-msal && yarn run lint",
18-
"test": "cd packages/react-aad-msal && yarn test",
19-
"build": "cd packages/react-aad-msal && yarn build"
16+
"start": "yarn workspace react-aad-msal start",
17+
"lint": "yarn workspace react-aad-msal lint",
18+
"test": "yarn workspace react-aad-msal test",
19+
"build": "yarn workspace react-aad-msal build"
2020
},
2121
"dependencies": {},
2222
"husky": {

samples/react-typescript/package.json

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
"name": "react-typescript-sample",
3+
"version": "1.0.0",
4+
"description": "A sample React application that demonstrates the Azure AD react component.",
5+
"private": true,
6+
"license": "MIT",
7+
"repository": {
8+
"type": "git",
9+
"url": "https://github.com/syncweek-react-aad/react-aad.git"
10+
},
11+
"author": "Laura Bochenek",
12+
"contributors": [
13+
"Laura Bochenek <[email protected]>",
14+
"Omeed Musavi <[email protected]>",
15+
"Lilian Kasem <[email protected]>",
16+
"Tess DiStefano <[email protected]>",
17+
"Lucas Huet-Hudson <[email protected]>",
18+
"Zach Miller <[email protected]>",
19+
"P.J. Little <[email protected]>",
20+
"Shawn Cicoria <[email protected]>",
21+
"Andrew Craswell <[email protected]>",
22+
"Björn Dalfors <[email protected]>"
23+
],
24+
"dependencies": {
25+
"@testing-library/jest-dom": "^4.2.4",
26+
"@testing-library/react": "^9.3.2",
27+
"@testing-library/user-event": "^7.1.2",
28+
"@types/jest": "^24.0.0",
29+
"@types/node": "^12.0.0",
30+
"@types/react": "^16.9.0",
31+
"@types/react-dom": "^16.9.0",
32+
"@types/react-redux": "^7.1.7",
33+
"msal": "^1.2.0",
34+
"react": "^16.12.0",
35+
"react-aad-msal": "^2.3.2",
36+
"react-dom": "^16.12.0",
37+
"react-redux": "^7.1.3",
38+
"react-scripts": "3.3.0",
39+
"redux": "^4.0.5",
40+
"typescript": "^3.7.5"
41+
},
42+
"devDependencies": {
43+
"rimraf": "^3.0.0"
44+
},
45+
"scripts": {
46+
"clean": "rimraf build",
47+
"start": "react-scripts start",
48+
"build": "react-scripts build",
49+
"test": "react-scripts test --env=jsdom",
50+
"eject": "react-scripts eject"
51+
},
52+
"eslintConfig": {
53+
"extends": "react-app"
54+
},
55+
"browserslist": {
56+
"production": [
57+
">0.2%",
58+
"not dead",
59+
"not ie < 11",
60+
"not op_mini all"
61+
],
62+
"development": [
63+
"last 1 chrome version",
64+
"last 1 firefox version",
65+
"last 1 safari version"
66+
]
67+
}
68+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!--
2+
A blank html helper file for authentication redirects.
3+
4+
If using the popup authentication method, point the redirectUrl to this file for a more performant authentication.
5+
Rather than the authentication popup loading the entire page in an iframe and downloading scripts/css twice,
6+
the MSAL library will use this blank HTML file as a valid route on the domain to store items in cache and deal
7+
with cookies.
8+
9+
If not using the popup authentication method, this file can still be used for refresh tokens, where the file will be loaded
10+
in the refresh iframe rather than reloading your entire site.
11+
-->
3.78 KB
Binary file not shown.
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6+
<meta name="theme-color" content="#000000">
7+
<!--
8+
manifest.json provides metadata used when your web app is added to the
9+
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
10+
-->
11+
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
12+
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
13+
<!--
14+
Notice the use of %PUBLIC_URL% in the tags above.
15+
It will be replaced with the URL of the `public` folder during the build.
16+
Only files inside the `public` folder can be referenced from the HTML.
17+
18+
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
19+
work correctly both with client-side routing and a non-root public URL.
20+
Learn how to configure a non-root public URL by running `npm run build`.
21+
-->
22+
<title>React App</title>
23+
</head>
24+
<body>
25+
<noscript>
26+
You need to enable JavaScript to run this app.
27+
</noscript>
28+
<div id="root"></div>
29+
<!--
30+
This HTML file is a template.
31+
If you open it directly in the browser, you will see an empty page.
32+
33+
You can add webfonts, meta tags, or analytics to this file.
34+
The build step will place the bundled scripts into the <body> tag.
35+
36+
To begin the development, run `npm start` or `yarn start`.
37+
To create a production bundle, use `npm run build` or `yarn build`.
38+
-->
39+
</body>
40+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"short_name": "React App",
3+
"name": "Create React App Sample",
4+
"icons": [
5+
{
6+
"src": "favicon.ico",
7+
"sizes": "64x64 32x32 24x24 16x16",
8+
"type": "image/x-icon"
9+
}
10+
],
11+
"start_url": "./index.html",
12+
"display": "standalone",
13+
"theme_color": "#000000",
14+
"background_color": "#ffffff"
15+
}

samples/react-typescript/src/App.css

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
.App {
2+
text-align: center;
3+
}
4+
5+
.App-header {
6+
background-color: #222;
7+
height: 25px;
8+
padding: 20px;
9+
color: white;
10+
margin-bottom: 2em;
11+
}
12+
13+
.App-title {
14+
font-size: 1.5em;
15+
margin: 0;
16+
}
17+
18+
.App-intro {
19+
font-size: large;
20+
}
21+
22+
.SampleContainer {
23+
width: 100%;
24+
display: flex;
25+
justify-content: center;
26+
}
27+
28+
.SampleBox {
29+
border: 1px solid black;
30+
width: 20em;
31+
margin: 2em;
32+
padding: 10px;
33+
border-radius: 10px;
34+
}
35+
36+
.SampleHeader {
37+
font-size: 1.25em;
38+
}
39+
40+
.Button {
41+
background-color: #00a1f1;
42+
border: none;
43+
color: white;
44+
display: inline-block;
45+
padding: 15px;
46+
font-size: 15px;
47+
cursor: pointer;
48+
}
49+
50+
.Button:disabled {
51+
background-color: grey;
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from "react";
2+
import ReactDOM from "react-dom";
3+
import App from "./App";
4+
5+
it("renders without crashing", () => {
6+
const div = document.createElement("div");
7+
ReactDOM.render(<App />, div);
8+
ReactDOM.unmountComponentAtNode(div);
9+
});

samples/react-typescript/src/App.tsx

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import React, { useState } from "react";
2+
import {
3+
AzureAD,
4+
AuthenticationState,
5+
IAzureADFunctionProps
6+
} from "react-aad-msal";
7+
import { basicReduxStore } from "./reduxStore";
8+
9+
// Import the authentication provider which holds the default settings
10+
import { authProvider } from "./authProvider";
11+
12+
import "./App.css";
13+
import { SampleBox } from "./SampleBox";
14+
15+
const App = () => {
16+
const [sampleType, setSampleType] = useState("");
17+
18+
const handleClick = (sampleType: string) => {
19+
setSampleType(sampleType);
20+
localStorage.setItem("sampleType", sampleType);
21+
};
22+
23+
return (
24+
<div className="App">
25+
<header className="App-header">
26+
<h1 className="App-title">Welcome to the react-aad-msal sample</h1>
27+
</header>
28+
29+
<AzureAD provider={authProvider} reduxStore={basicReduxStore}>
30+
{({
31+
accountInfo,
32+
authenticationState,
33+
error
34+
}: IAzureADFunctionProps) => {
35+
return (
36+
<React.Fragment>
37+
{authenticationState === AuthenticationState.Unauthenticated && (
38+
<div>
39+
<button
40+
onClick={() => handleClick("popup")}
41+
className="Button"
42+
>
43+
Popup Sample
44+
</button>{" "}
45+
<button
46+
onClick={() => handleClick("redirect")}
47+
className="Button"
48+
>
49+
Redirect Sample
50+
</button>
51+
</div>
52+
)}
53+
54+
<div className="SampleContainer">
55+
<SampleBox sampleType={sampleType} />
56+
<div className="SampleBox">
57+
<h2 className="SampleHeader">Authenticated Values</h2>
58+
<p>
59+
When logged in, this box will show your tokens and user info
60+
</p>
61+
{accountInfo && (
62+
<div style={{ wordWrap: "break-word" }}>
63+
<p>
64+
<span style={{ fontWeight: "bold" }}>ID Token:</span>{" "}
65+
{accountInfo.jwtIdToken}
66+
</p>
67+
<p>
68+
<span style={{ fontWeight: "bold" }}>Username:</span>{" "}
69+
{accountInfo.account.userName}
70+
</p>
71+
<p>
72+
<span style={{ fontWeight: "bold" }}>
73+
Access Token:
74+
</span>{" "}
75+
{accountInfo.jwtAccessToken}
76+
</p>
77+
<p>
78+
<span style={{ fontWeight: "bold" }}>Name:</span>{" "}
79+
{accountInfo.account.name}
80+
</p>
81+
</div>
82+
)}
83+
</div>
84+
<div className="SampleBox">
85+
<h2 className="SampleHeader">Errors</h2>
86+
<p>
87+
If authentication fails, this box will have the errors that
88+
occured
89+
</p>
90+
{error && (
91+
<div style={{ wordWrap: "break-word" }}>
92+
<p>
93+
<span style={{ fontWeight: "bold" }}>errorCode:</span>{" "}
94+
{error.errorCode}
95+
</p>
96+
<p>
97+
<span style={{ fontWeight: "bold" }}>
98+
errorMessage:
99+
</span>{" "}
100+
{error.errorMessage}
101+
</p>
102+
</div>
103+
)}
104+
</div>
105+
</div>
106+
</React.Fragment>
107+
);
108+
}}
109+
</AzureAD>
110+
</div>
111+
);
112+
};
113+
114+
export default App;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from "react";
2+
import { MsalAuthProvider } from "react-aad-msal";
3+
4+
interface Props {
5+
provider: MsalAuthProvider;
6+
}
7+
8+
const GetTokenButton = ({ provider }: Props) => {
9+
const getAuthToken = async () => {
10+
alert((await provider.getAccessToken()).accessToken);
11+
};
12+
13+
return (
14+
<div style={{ margin: "40px 0" }}>
15+
<p>
16+
You can use the auth provider to get a fresh token. If a valid token is
17+
in cache it will be returned, otherwise a fresh token will be requested.
18+
If the request fails, the user will be forced to login again.
19+
</p>
20+
<button onClick={getAuthToken} className="Button">
21+
Get Access Token
22+
</button>
23+
</div>
24+
);
25+
};
26+
27+
export default GetTokenButton;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from "react";
2+
import { MsalAuthProvider } from "react-aad-msal";
3+
4+
interface Props {
5+
provider: MsalAuthProvider;
6+
}
7+
8+
const GetTokenButton = ({ provider }: Props) => {
9+
const getAuthToken = async () => {
10+
alert((await provider.getIdToken()).idToken.rawIdToken);
11+
};
12+
13+
return (
14+
<div style={{ margin: "40px 0" }}>
15+
<p>
16+
It's also possible to renew the IdToken. If a valid token is in the
17+
cache, it will be returned. Otherwise a renewed token will be requested.
18+
If the request fails, the user will be forced to login again.
19+
</p>
20+
<button onClick={getAuthToken} className="Button">
21+
Get IdToken
22+
</button>
23+
</div>
24+
);
25+
};
26+
27+
export default GetTokenButton;

0 commit comments

Comments
 (0)