forked from Code-4-Community/scaffolding
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
login page and protected routes (#75)
* migrate from cognito implicit grant to code grant flow * implement login page and protected routes * slightly better login page
- Loading branch information
Showing
13 changed files
with
222 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { IsString, IsNotEmpty, IsNumberString } from 'class-validator'; | ||
|
||
export class TokenExchangeResponseDTO { | ||
@IsNotEmpty() | ||
@IsString() | ||
access_token: string; | ||
|
||
@IsString() | ||
refresh_token: string; | ||
|
||
@IsString() | ||
id_token: string; | ||
|
||
@IsString() | ||
token_type: string; | ||
|
||
@IsNumberString() | ||
expires_in: number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,33 @@ | ||
import { useEffect } from 'react'; | ||
import { createBrowserRouter, RouterProvider } from 'react-router-dom'; | ||
import { BrowserRouter, Route, Routes } from 'react-router-dom'; | ||
import { useState } from 'react'; | ||
|
||
import apiClient from '@api/apiClient'; | ||
import Root from '@containers/root'; | ||
import NotFound from '@containers/404'; | ||
import Test from '@containers/test'; | ||
|
||
const router = createBrowserRouter([ | ||
{ | ||
path: '/', | ||
element: <Root />, | ||
errorElement: <NotFound />, | ||
}, | ||
{ | ||
path: '/test', | ||
element: <Test />, | ||
}, | ||
]); | ||
import LoginContext from '@components/LoginPage/LoginContext'; | ||
import ProtectedRoutes from '@components/ProtectedRoutes'; | ||
import LoginPage from '@components/LoginPage'; | ||
|
||
export const App: React.FC = () => { | ||
return <RouterProvider router={router} />; | ||
const [token, setToken] = useState<string>(''); | ||
return ( | ||
<LoginContext.Provider value={{ setToken, token }}> | ||
<BrowserRouter> | ||
<Routes> | ||
<Route path="/login" element={<LoginPage />} /> | ||
|
||
{/* Protected Routes */} | ||
<Route element={<ProtectedRoutes token={token} />}> | ||
<Route path="/" element={<Root />} /> | ||
<Route path="/test" element={<Test />} /> | ||
</Route> | ||
|
||
{/* 404 Route */} | ||
<Route path="*" element={<NotFound />} /> | ||
</Routes> | ||
</BrowserRouter> | ||
</LoginContext.Provider> | ||
); | ||
}; | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { createContext } from 'react'; | ||
|
||
export interface LoginContextType { | ||
setToken: (token: string) => void; | ||
token: string; | ||
} | ||
|
||
// Login Context is used to store user's access token | ||
const LoginContext = createContext<LoginContextType | null>(null); | ||
export default LoginContext; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { useEffect } from 'react'; | ||
import apiClient from '@api/apiClient'; | ||
import useLoginContext from './useLoginContext'; | ||
import { useNavigate } from 'react-router-dom'; | ||
import { Button, Stack } from '@mui/material'; | ||
|
||
/** | ||
* Login Page component first checks if the user has been redirected from the | ||
* Cognito login page with an authorization code. If the code is present, it | ||
* fetches the user's access token and stores it in the context. | ||
*/ | ||
export default function LoginPage() { | ||
const { setToken } = useLoginContext(); | ||
const navigate = useNavigate(); | ||
useEffect(() => { | ||
const urlParams = new URLSearchParams(window.location.search); | ||
const authCode = urlParams.get('code'); | ||
|
||
async function getToken() { | ||
if (authCode) { | ||
try { | ||
const token = await apiClient.getToken(authCode); | ||
setToken(token); | ||
navigate('/'); | ||
} catch (error) { | ||
console.error('Error fetching token:', error); | ||
} | ||
} | ||
} | ||
getToken(); | ||
}, [navigate, setToken]); | ||
return ( | ||
<Stack | ||
width="100vw" | ||
height="100vh" | ||
justifyContent="center" | ||
alignItems="center" | ||
> | ||
<Button | ||
variant="contained" | ||
color="primary" | ||
href="https://scaffolding.auth.us-east-2.amazoncognito.com/login?client_id=4c5b8m6tno9fvljmseqgmk82fv&response_type=code&scope=email+openid&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Flogin" | ||
> | ||
Login | ||
</Button> | ||
</Stack> | ||
); | ||
} |
21 changes: 21 additions & 0 deletions
21
apps/frontend/src/components/LoginPage/useLoginContext.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { useContext } from 'react'; | ||
import LoginContext, { LoginContextType } from './LoginContext'; | ||
|
||
/** | ||
* Custom hook to access the LoginContext. | ||
* | ||
* @throws It will throw an error if the `LoginContext` is null. | ||
* | ||
* @returns context - the context value for managing login state | ||
*/ | ||
const useLoginContext = (): LoginContextType => { | ||
const context = useContext(LoginContext); | ||
|
||
if (context === null) { | ||
throw new Error('Login context is null.'); | ||
} | ||
|
||
return context; | ||
}; | ||
|
||
export default useLoginContext; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Navigate, Outlet } from 'react-router-dom'; | ||
|
||
/** | ||
* ProtectedRoutes renders the children components only | ||
* if the user is authenticated (i.e if an access token exists). | ||
* If the user is not authenticated, it redirects to the login page. | ||
*/ | ||
function ProtectedRoutes({ token }: { token: string }) { | ||
return token ? <Outlet /> : <Navigate to="/login" />; | ||
} | ||
|
||
export default ProtectedRoutes; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters