From d0a1457f44a3d8993b57106e5e681c4e51fe8e7d Mon Sep 17 00:00:00 2001 From: Muhammad Saad Date: Wed, 15 Dec 2021 17:51:19 +0500 Subject: [PATCH] feat: added authorization route for web (#37) --- docker-compose.yml | 2 +- web/src/App.tsx | 12 +++++- web/src/components/login.tsx | 75 +++++++++++++++++++++++++++------ web/src/components/useTokens.ts | 15 ++----- 4 files changed, 78 insertions(+), 26 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8882785..f7368c7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: context: . dockerfile: DockerfileApi environment: - MODE: ${MODE} + MODE: 'server' CORS: ${CORS} PORT: ${PORT_API} PORT_WEB: ${PORT_WEB} diff --git a/web/src/App.tsx b/web/src/App.tsx index 22ec1e7..e298fe0 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -19,7 +19,14 @@ function App() {
- + + + + + + + + ) @@ -39,6 +46,9 @@ function App() { + + + diff --git a/web/src/components/login.tsx b/web/src/components/login.tsx index 83c99c2..c212b0e 100644 --- a/web/src/components/login.tsx +++ b/web/src/components/login.tsx @@ -1,7 +1,8 @@ import React, { useState } from 'react' +import { useLocation } from 'react-router-dom' import PropTypes from 'prop-types' -import { CssBaseline, Box, TextField, Button } from '@mui/material' +import { CssBaseline, Box, TextField, Button, Typography } from '@mui/material' const headers = { Accept: 'application/json', @@ -18,7 +19,12 @@ const getAuthCode = async (credentials: any) => { method: 'POST', headers, body: JSON.stringify(credentials) - }).then((data) => data.json()) + }).then(async (response) => { + const resText = await response.text() + if (response.status !== 200) throw resText + + return JSON.parse(resText) + }) } const getTokens = async (payload: any) => { return fetch(`${baseUrl}/SASjsApi/auth/token`, { @@ -28,26 +34,62 @@ const getTokens = async (payload: any) => { }).then((data) => data.json()) } -const Login = ({ setTokens }: any) => { - const [username, setUserName] = useState() - const [password, setPassword] = useState() +const Login = ({ setTokens, getCodeOnly }: any) => { + const location = useLocation() + const [username, setUserName] = useState('') + const [password, setPassword] = useState('') + const [errorMessage, setErrorMessage] = useState('') + let error: boolean + const [displayCode, setDisplayCode] = useState(null) const handleSubmit = async (e: any) => { + error = false + setErrorMessage('') e.preventDefault() - const { REACT_APP_CLIENT_ID: clientId } = process.env + let { REACT_APP_CLIENT_ID: clientId } = process.env + + if (getCodeOnly) { + const params = new URLSearchParams(location.search) + const responseType = params.get('response_type') + if (responseType === 'code') + clientId = params.get('client_id') ?? undefined + } const { code } = await getAuthCode({ clientId, username, password + }).catch((err: string) => { + error = true + setErrorMessage(err) + return {} }) - const { accessToken, refreshToken } = await getTokens({ - clientId, - code - }) + if (!error) { + if (getCodeOnly) return setDisplayCode(code) - setTokens(accessToken, refreshToken) + const { accessToken, refreshToken } = await getTokens({ + clientId, + code + }) + + setTokens(accessToken, refreshToken) + } + } + + if (displayCode) { + return ( + + +
+

Authorization Code

+ + {displayCode} + + +
+
+ ) } return ( @@ -61,7 +103,12 @@ const Login = ({ setTokens }: any) => { >
-

Welcome to SASjs Server!

+

Welcome to SASjs Server!

+ {getCodeOnly && ( +

+ Provide credentials to get authorization code. +

+ )}
{ onChange={(e: any) => setPassword(e.target.value)} required /> + {errorMessage && {errorMessage}} @@ -88,7 +136,8 @@ const Login = ({ setTokens }: any) => { } Login.propTypes = { - setTokens: PropTypes.func.isRequired + setTokens: PropTypes.func, + getCodeOnly: PropTypes.bool } export default Login diff --git a/web/src/components/useTokens.ts b/web/src/components/useTokens.ts index a9d0ccb..17e30a2 100644 --- a/web/src/components/useTokens.ts +++ b/web/src/components/useTokens.ts @@ -3,15 +3,8 @@ import { useEffect, useState } from 'react' export default function useTokens() { const getTokens = () => { - const accessTokenString = localStorage.getItem('accessToken') - const accessToken: string = accessTokenString - ? JSON.parse(accessTokenString) - : undefined - - const refreshTokenString = localStorage.getItem('refreshToken') - const refreshToken: string = refreshTokenString - ? JSON.parse(refreshTokenString) - : undefined + const accessToken = localStorage.getItem('accessToken') + const refreshToken = localStorage.getItem('refreshToken') if (accessToken && refreshToken) { setAxiosRequestHeader(accessToken) @@ -31,8 +24,8 @@ export default function useTokens() { setAxiosResponse(setTokens) const saveTokens = (accessToken: string, refreshToken: string) => { - localStorage.setItem('accessToken', JSON.stringify(accessToken)) - localStorage.setItem('refreshToken', JSON.stringify(refreshToken)) + localStorage.setItem('accessToken', accessToken) + localStorage.setItem('refreshToken', refreshToken) setAxiosRequestHeader(accessToken) setTokens({ accessToken, refreshToken }) }