├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.js
├── App.test.js
├── authConfig.js
├── components
├── Callback.js
└── Login.js
├── index.css
├── index.js
├── reportWebVitals.js
└── style.css
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Readme
2 |
3 | Please follow the detailed instructions on how to run this React sample with ZITADEL [here](https://zitadel.com/docs/guides/start/quickstart).
4 |
5 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
6 |
7 | ## Available Scripts
8 |
9 | In the project directory, you can run:
10 |
11 | ### `npm start`
12 |
13 | Runs the app in the development mode.\
14 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
15 |
16 | The page will reload when you make changes.\
17 | You may also see any lint errors in the console.
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test2",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.5",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "oidc-client-ts": "^2.2.0",
10 | "react": "^18.2.0",
11 | "react-dom": "^18.2.0",
12 | "react-router-dom": "^6.6.1",
13 | "react-scripts": "5.0.1",
14 | "stream": "^0.0.2",
15 | "util": "^0.12.5",
16 | "web-vitals": "^2.1.4"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test",
22 | "eject": "react-scripts eject"
23 | },
24 | "eslintConfig": {
25 | "extends": [
26 | "react-app",
27 | "react-app/jest"
28 | ]
29 | },
30 | "browserslist": {
31 | "production": [
32 | ">0.2%",
33 | "not dead",
34 | "not op_mini all"
35 | ],
36 | "development": [
37 | "last 1 chrome version",
38 | "last 1 firefox version",
39 | "last 1 safari version"
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zitadel/react-user-authentication/fb2d8dd09a0d03c548808e2c5004c578bbe3b24f/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zitadel/react-user-authentication/fb2d8dd09a0d03c548808e2c5004c578bbe3b24f/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zitadel/react-user-authentication/fb2d8dd09a0d03c548808e2c5004c578bbe3b24f/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
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 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { BrowserRouter, Routes, Route } from "react-router-dom";
3 | import Login from "./components/Login";
4 | import Callback from "./components/Callback";
5 | import authConfig from "./authConfig";
6 | import { UserManager, WebStorageStateStore } from "oidc-client-ts";
7 |
8 | function App() {
9 | const userManager = new UserManager({
10 | userStore: new WebStorageStateStore({ store: window.localStorage }),
11 | ...authConfig,
12 | });
13 |
14 | function authorize() {
15 | userManager.signinRedirect({ state: "a2123a67ff11413fa19217a9ea0fbad5" });
16 | }
17 |
18 | function clearAuth() {
19 | userManager.signoutRedirect();
20 | }
21 |
22 | const [authenticated, setAuthenticated] = useState(null);
23 | const [userInfo, setUserInfo] = useState(null);
24 |
25 | useEffect(() => {
26 | userManager.getUser().then((user) => {
27 | if (user) {
28 | setAuthenticated(true);
29 | } else {
30 | setAuthenticated(false);
31 | }
32 | });
33 | }, [userManager]);
34 |
35 | return (
36 |
37 |
38 | }
41 | />
42 |
53 | }
54 | />
55 |
56 |
57 | );
58 | }
59 |
60 | export default App;
61 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render();
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/src/authConfig.js:
--------------------------------------------------------------------------------
1 | const authConfig = {
2 | authority: 'https://some_text.zitadel.cloud/', //Replace with your issuer URL
3 | client_id: 'ABC123@Project', //Replace with your client id
4 | redirect_uri: 'http://localhost:3000/callback',
5 | response_type: 'code',
6 | scope: 'openid profile email',
7 | post_logout_redirect_uri: 'http://localhost:3000/',
8 | userinfo_endpoint: 'https://instance-some_text.zitadel.cloud/oidc/v1/userinfo', //Replace with your user-info endpoint
9 | response_mode: 'query',
10 | code_challenge_method: 'S256',
11 | };
12 |
13 | export default authConfig;
14 |
--------------------------------------------------------------------------------
/src/components/Callback.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import authConfig from '../authConfig';
3 |
4 | const Callback = ({ auth, setAuth, userManager, userInfo, setUserInfo, handleLogout }) => {
5 |
6 | useEffect(() => {
7 | if (auth === null) {
8 | userManager.signinRedirectCallback().then((user) => {
9 | if (user) {
10 | setAuth(true);
11 | const access_token = user.access_token;
12 | // Make a request to the user info endpoint using the access token
13 | fetch(authConfig.userinfo_endpoint, {
14 | headers: {
15 | 'Authorization': `Bearer ${access_token}`
16 | }
17 | })
18 | .then(response => response.json())
19 | .then(userInfo => {
20 | setUserInfo(userInfo);
21 | });
22 | } else {
23 | setAuth(false);
24 | }
25 | }).catch((error) => {
26 | setAuth(false);
27 | });
28 | }
29 | }, [auth, userManager, setAuth]);
30 |
31 |
32 | if (auth === true && userInfo) {
33 | return (
34 |
35 |
Welcome, {userInfo.name}!
36 | Your ZITADEL Profile Information
37 | Name: {userInfo.name}
38 | Email: {userInfo.email}
39 | Email Verified: {userInfo.email_verified? "Yes": "No"}
40 | Locale: {userInfo.locale}
41 |
42 |
43 |
44 | );
45 | }
46 | else {
47 | return Loading...
;
48 | }
49 |
50 | };
51 |
52 | export default Callback;
53 |
54 |
--------------------------------------------------------------------------------
/src/components/Login.js:
--------------------------------------------------------------------------------
1 | import { Navigate } from "react-router-dom";
2 |
3 | const Login = ({ auth, handleLogin, userManager }) => {
4 | return (
5 |
6 | {auth === null &&
Loading...
}
7 | {auth === false && (
8 |
9 |
Welcome!
10 |
18 |
19 | )}
20 | {auth &&
}
21 |
22 | );
23 | };
24 |
25 | export default Login;
26 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './style.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | /* The body element covers the entire page, so setting the background color here
2 | will set the background color for the whole page */
3 | body {
4 | font-family: 'Open Sans', sans-serif;
5 | /* The hex code for the light blue color from the image is #9fd3e0 */
6 | background-color: #9fd3e0;
7 | /* Center the text in the body element */
8 | text-align: center;
9 | }
10 |
11 | /* The h1, h2, and h3 elements are used for headings */
12 | h1, h2, h3 {
13 | /* The hex code for the dark blue color from the image is #2c3e50 */
14 | color: #2c3e50;
15 | text-align: center;
16 | }
17 |
18 | /* The button element represents a clickable button */
19 | button {
20 | /* The hex code for the light purple color from the image is #9b59b6 */
21 | background-color: #9b59b6;
22 | /* The hex code for the white color is #ffffff */
23 | color: #ffffff;
24 | /* Add some padding and a border to the button */
25 | padding: 10px 20px;
26 | border: none;
27 | /* Add some hover effect to the button */
28 | cursor: pointer;
29 | }
30 |
31 | button:hover {
32 | /* The hex code for the dark purple color from the image is #8e44ad */
33 | background-color: #8e44ad;
34 | }
35 |
--------------------------------------------------------------------------------