Skip to content

Commit

Permalink
Okta login, profile working, needs TDM authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
entrotech committed Jan 20, 2024
1 parent 052b77a commit 76f0098
Show file tree
Hide file tree
Showing 8 changed files with 825 additions and 224 deletions.
849 changes: 636 additions & 213 deletions client/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@okta/okta-auth-js": "^7.5.0",
"@okta/okta-react": "^6.7.0",
"@react-pdf/renderer": "^3.1.9",
"axios": "^1.6.1",
"clsx": "^2.0.0",
Expand Down
11 changes: 11 additions & 0 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import ResetPassword from "./components/Authorization/ResetPassword";
import ForgotPassword from "./components/Authorization/ForgotPassword";
import Feedback from "./components/Feedback/FeedbackPage";
import ErrorPage from "./components/ErrorPage";
import ProfilePage from "./components/Okta/ProfilePage";
import { LoginCallback } from "@okta/okta-react";

const calculationPath = "/calculation/:page/:projectId?/*";

Expand Down Expand Up @@ -133,10 +135,19 @@ const App = ({
element={<TermsAndConditionsPage />}
/>
<Route path="/privacypolicy" element={<PrivacyPolicy />} />
<Route path="/profile" element={<ProfilePage />} />
<Route path="/unauthorized" element={<Unauthorized />} />
<Route path="/register/:email?" element={<Register />} />
<Route path="/updateaccount/:email?" element={<UpdateAccount />} />
<Route path="/confirm/:token?" element={<ConfirmEmail />} />
<Route
path="/login/callback"
element={
<LoginCallback
loadingElement={<h3 id="loading-icon">Loading...</h3>}
/>
}
/>
<Route path="/login/:email?" element={<Login />} />
<Route path="/forgotpassword" element={<ForgotPassword />} />
<Route path="/resetPassword/:token" element={<ResetPassword />} />
Expand Down
35 changes: 24 additions & 11 deletions client/src/components/Layout/ClientAreaLayout.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ import Footer from "./Footer";
import TermsAndConditionsModal from "../TermsAndConditions/TermsAndConditionsModal";
import ChecklistModal from "../Checklist/ChecklistModal";

import { useNavigate } from "react-router-dom";
import { Security } from "@okta/okta-react";
import { OktaAuth, toRelativeUrl } from "@okta/okta-auth-js";
import config from "../../okta.config";

const oktaAuth = new OktaAuth(config.oidc);

const useStyles = createUseStyles({
app: {
flex: "1 0 auto",
Expand All @@ -23,20 +30,26 @@ const ClientAreaLayout = ({
toggleChecklistModal
}) => {
const classes = useStyles();
const navigate = useNavigate();
const restoreOriginalUri = (_oktaAuth, originalUri) => {
navigate(toRelativeUrl(originalUri || "/", window.location.origin));
};

return (
<div className={classes.app} id="app-container" ref={appContainerRef}>
<TermsAndConditionsModal
hasAcceptedTerms={hasAcceptedTerms}
onAcceptTerms={onAcceptTerms}
/>
<ChecklistModal
checklistModalOpen={checklistModalOpen}
toggleChecklistModal={toggleChecklistModal}
/>
<Header />
<Outlet />
<Footer toggleChecklistModal={toggleChecklistModal} />
<Security oktaAuth={oktaAuth} restoreOriginalUri={restoreOriginalUri}>
<TermsAndConditionsModal
hasAcceptedTerms={hasAcceptedTerms}
onAcceptTerms={onAcceptTerms}
/>
<ChecklistModal
checklistModalOpen={checklistModalOpen}
toggleChecklistModal={toggleChecklistModal}
/>
<Header />
<Outlet />
<Footer toggleChecklistModal={toggleChecklistModal} />
</Security>
</div>
);
};
Expand Down
3 changes: 3 additions & 0 deletions client/src/components/Layout/NavBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { NavLink } from "react-router-dom";
import NavBarLogin from "./NavBarLogin";
import PropTypes from "prop-types";

import LoginButton from "../Okta/LoginButton";

const useStyles = createUseStyles({
navbar: {
flexGrow: "1",
Expand Down Expand Up @@ -176,6 +178,7 @@ const NavBar = ({ navbarOpen, setNavbarOpen }) => {
navbarOpen={navbarOpen}
handleHamburgerMenuClick={handleHamburgerMenuClick}
/>
<LoginButton />
</ul>
);
};
Expand Down
36 changes: 36 additions & 0 deletions client/src/components/Okta/LoginButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { useState, useEffect } from "react";
import { useOktaAuth } from "@okta/okta-react";

const LoginButton = () => {
const { authState, oktaAuth } = useOktaAuth();
const [oktaUserInfo, setOktaUserInfo] = useState(null);

useEffect(() => {
if (!authState || !authState.isAuthenticated) {
// When user isn't authenticated, forget any user info
setOktaUserInfo(null);
} else {
oktaAuth.getUser().then(info => {
setOktaUserInfo(info);
});
}
}, [authState, oktaAuth]); // Update if authState changes

const handleLogin = async () => {
await oktaAuth.signInWithRedirect();
};

const handleLogout = async () => {
await oktaAuth.signOut();
};

if (!oktaUserInfo)
return <button onClick={handleLogin}>Login / Register</button>;
return (
<div>
<button onClick={handleLogout}>Logout</button>
</div>
);
};

export default LoginButton;
90 changes: 90 additions & 0 deletions client/src/components/Okta/ProfilePage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useState, useEffect } from "react";
import { useOktaAuth } from "@okta/okta-react";

import { createUseStyles, useTheme } from "react-jss";

import ContentContainer from "../Layout/ContentContainer";

const useStyles = createUseStyles(theme => ({
content: {
maxWidth: "1000px"
},
heading: {
color: theme.colorPrimary
}
}));

const ProfilePage = () => {
const theme = useTheme();
const classes = useStyles(theme);
const { authState, oktaAuth } = useOktaAuth();
const [userInfo, setUserInfo] = useState(null);

useEffect(() => {
if (!authState || !authState.isAuthenticated) {
// When user isn't authenticated, forget any user info
setUserInfo(null);
} else {
setUserInfo(authState.idToken.claims);
// get user information from `/userinfo` endpoint
oktaAuth.getUser().then(info => {
setUserInfo(info);
});
}
}, [authState, oktaAuth]); // Update if authState changes

if (!userInfo) {
return (
<div>
<p>Fetching user profile...</p>
</div>
);
}

return (
<ContentContainer>
<h1>Ojta User Profile (ID Token Claims) </h1>
<div className={classes.content}>
<p>
Below is the information from your ID token which was obtained during
the &nbsp;
<a href="https://developer.okta.com/docs/guides/implement-auth-code-pkce">
PKCE Flow
</a>{" "}
and is now stored in local storage.
</p>
<p>
This route is protected with the <code>&lt;SecureRoute&gt;</code>{" "}
component, which will ensure that this page cannot be accessed until
you have authenticated.
</p>
<h2>Auth</h2>
<pre>{JSON.stringify(authState, null, 2)}</pre>
<h2>Claims</h2>
<table>
<thead>
<tr>
<th>Claim</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{Object.entries(userInfo).map(claimEntry => {
const claimName = claimEntry[0];
const claimValue = claimEntry[1];
const claimId = `claim-${claimName}`;
return (
<tr key={claimName}>
<td>{claimName}</td>
<td id={claimId}>{claimValue.toString()}</td>
</tr>
);
})}
</tbody>
</table>
</div>
</ContentContainer>
);
};

export default ProfilePage;
23 changes: 23 additions & 0 deletions client/src/okta.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const OKTA_TESTING_DISABLEHTTPSCHECK = true;
// process.env.OKTA_TESTING_DISABLEHTTPSCHECK || false;
const REDIRECT_URI = `${window.location.origin}/login/callback`;

// Dev Okta
const ISSUER = "https://dev-50564150.okta.com/oauth2/default";
const CLIENT_ID = "0oaehwjjhx70xRh0O5d7";

// UAT Okta
// const ISSUER = "https://lacitypublic.oktapreview.com/oauth2/default"
// const CLIENT_ID = "0oabp5dgnwuGTqt5n1d7"

// eslint-disable-next-line
export default {
oidc: {
clientId: CLIENT_ID,
issuer: ISSUER,
redirectUri: REDIRECT_URI,
scopes: ["openid", "profile", "email"],
pkce: true,
disableHttpsCheck: OKTA_TESTING_DISABLEHTTPSCHECK
}
};

0 comments on commit 76f0098

Please sign in to comment.