From c6116a7d63fa943b4fd1d20648b38936e459eb52 Mon Sep 17 00:00:00 2001 From: reslene Date: Tue, 2 May 2023 15:24:15 +0200 Subject: [PATCH] fix(Auth): get current user on root instead of topbar to avoid sync issue with refresh token timeout. Signed-off-by: reslene --- app/root.tsx | 29 +++++++++++-------- .../Layout/components/Topbar/Topbar.tsx | 24 +-------------- app/src/contexts/service.ts | 2 -- app/src/utils/auth.server.ts | 13 +++++++++ 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/app/root.tsx b/app/root.tsx index 377cadde..173b4483 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -37,17 +37,13 @@ import { getRoute, OVERVIEW_ROUTE } from '~/src/components/Layout/routes'; import ClientStyleContext from '~/src/contexts/clientStyleContext'; import { ServiceContext } from '~/src/contexts/service'; import { Errors } from '~/src/types/generic'; -import { - Authentication, - CurrentUser, - errorsMap, - logger, -} from '~/src/utils/api'; +import { Authentication, errorsMap, logger } from '~/src/utils/api'; import { ReactApiClient } from '~/src/utils/api.client'; import { AUTH_CALLBACK_ROUTE, COOKIE_NAME, decrypt, + getCurrentUser, getJwtPayload, getOpenIdConfig, getSession, @@ -93,6 +89,19 @@ export const loader: LoaderFunction = async ({ request }) => { await withSession(request, async () => { const sessionHolder = decrypt(cookie); const payload = getJwtPayload(sessionHolder); + const user = await getCurrentUser( + openIdConfig, + sessionHolder.access_token + ); + + const pseudo = user && user.email ? user.email.split('@')[0] : undefined; + + const currentUser = { + ...user, + avatarLetter: pseudo ? pseudo.split('')[0].toUpperCase() : undefined, + scp: payload ? payload.scp : [], + pseudo, + }; return { metas: { @@ -100,9 +109,7 @@ export const loader: LoaderFunction = async ({ request }) => { openIdConfig, api: process.env.API_URL, }, - currentUser: { - scp: payload ? payload.scp : [], - }, + currentUser, }; }) ); @@ -267,7 +274,6 @@ const Document = withEmotionCache( // https://remix.run/api/conventions#route-filenames export default function App() { const { metas, currentUser } = useLoaderData(); - const [user, setUser] = useState(currentUser); const { t } = useTranslation(); const [loading, _load, stopLoading] = useOpen(true); const [feedback, setFeedback] = useState({ @@ -331,8 +337,7 @@ export default function App() { setUser(user), + currentUser, metas, snackbar: displayFeedback, }} diff --git a/app/src/components/Layout/components/Topbar/Topbar.tsx b/app/src/components/Layout/components/Topbar/Topbar.tsx index a96bb709..2566f78c 100644 --- a/app/src/components/Layout/components/Topbar/Topbar.tsx +++ b/app/src/components/Layout/components/Topbar/Topbar.tsx @@ -23,7 +23,6 @@ import Search from '~/src/components/Search'; import { useService } from '~/src/hooks/useService'; import useSimpleMediaQuery from '~/src/hooks/useSimpleMediaQuery'; import { Gateway } from '~/src/types/gateway'; -import { CurrentUser } from '~/src/utils/api'; import { ReactApiClient } from '~/src/utils/api.client'; const Topbar: FunctionComponent = ({ resized, onResize }) => { @@ -31,7 +30,7 @@ const Topbar: FunctionComponent = ({ resized, onResize }) => { const { t } = useTranslation(); const { isMobile } = useSimpleMediaQuery(); const [gateway, setGateway] = useState<{ region: string; env: string }>(); - const { api, setCurrentUser, currentUser, metas } = useService(); + const { currentUser, metas } = useService(); const [anchorElUser, setAnchorElUser] = React.useState( null ); @@ -73,26 +72,6 @@ const Topbar: FunctionComponent = ({ resized, onResize }) => { window.location.href = `${metas.origin}/auth/redirect-logout`; }; - const getCurrentUser = async () => { - try { - const user = await api.getResource( - `${metas.openIdConfig.userinfo_endpoint.split('api')[1]}` - ); - if (user) { - const pseudo = - user && user.email ? user.email.split('@')[0] : undefined; - - setCurrentUser({ - ...user, - avatarLetter: pseudo ? pseudo.split('')[0].toUpperCase() : undefined, - pseudo, - }); - } - } catch (e) { - console.info('Current user could not be retrieved yet'); - } - }; - useEffect(() => { (async () => { const client = new ReactApiClient(); @@ -101,7 +80,6 @@ const Topbar: FunctionComponent = ({ resized, onResize }) => { if (gateway) { setGateway(gateway); } - await getCurrentUser(); })(); }, []); diff --git a/app/src/contexts/service.ts b/app/src/contexts/service.ts index 35fa31d4..209d2948 100644 --- a/app/src/contexts/service.ts +++ b/app/src/contexts/service.ts @@ -4,12 +4,10 @@ import { ApiClient, CurrentUser } from '~/src/utils/api'; import { OpenIdConfiguration } from '~/src/utils/auth.server'; export type SnackbarSetter = (message?: string) => void; -export type SetCurrentUser = (_user: CurrentUser) => void; export type ServiceContext = { api: ApiClient; currentUser: CurrentUser; - setCurrentUser: SetCurrentUser; metas: { origin: string; openIdConfig: OpenIdConfiguration; diff --git a/app/src/utils/auth.server.ts b/app/src/utils/auth.server.ts index b98e5ea4..ac380a65 100644 --- a/app/src/utils/auth.server.ts +++ b/app/src/utils/auth.server.ts @@ -12,6 +12,7 @@ import { ObjectOf } from '~/src/types/generic'; import { API_AUTH, Authentication, + CurrentUser, JwtPayload, Methods, SessionWrapper, @@ -89,6 +90,18 @@ export const getOpenIdConfig = async (): Promise => { }); }; +export const getCurrentUser = async ( + openIdConfig: OpenIdConfiguration, + token: string +): Promise => + fetch(openIdConfig.userinfo_endpoint, { + headers: { Authorization: `Bearer ${token}` }, + }) + .then(async (response) => response.json()) + .catch(() => { + throw new Error('Error while fetching current user'); + }); + export const getJwtPayload = ( decryptedCookie: Authentication ): JwtPayload | undefined =>