diff --git a/client/components/auth/AuthLoader.tsx b/client/components/auth/AuthLoader.tsx index 2f18c7c..29e937f 100644 --- a/client/components/auth/AuthLoader.tsx +++ b/client/components/auth/AuthLoader.tsx @@ -1,4 +1,4 @@ -import { fetchAuthSession, signOut } from 'aws-amplify/auth'; +import { fetchAuthSession, getCurrentUser, signOut } from 'aws-amplify/auth'; import { Hub } from 'aws-amplify/utils'; import { isAxiosError } from 'axios'; import { useAlert } from 'components/alert/useAlert'; @@ -25,14 +25,10 @@ export const AuthLoader = () => { }, [catchApiErr, setUser]); useEffect(() => { - const controller = new AbortController(); - apiClient.private.me - .$get({ config: { signal: controller.signal } }) - .then(setUser) - .catch((e) => (isAxiosError(e) && e.response?.status === 401 ? setUser(null) : null)); - - return () => controller.abort(); - }, [setUser]); + getCurrentUser() + .then(updateCookie) + .catch(() => setUser(null)); + }, [setUser, updateCookie]); useEffect(() => { const useId = apiAxios.interceptors.response.use(undefined, async (err) => { @@ -56,17 +52,15 @@ export const AuthLoader = () => { async (data) => { switch (data.payload.event) { case 'customOAuthState': - break; case 'signInWithRedirect': - break; case 'signInWithRedirect_failure': + case 'tokenRefresh': break; case 'signedOut': await apiClient.session.$delete().catch(catchApiErr); setUser(null); break; case 'signedIn': - case 'tokenRefresh': await updateCookie().catch(catchApiErr); break; case 'tokenRefresh_failure': diff --git a/compose.yml b/compose.yml index 8a6756a..889bebc 100644 --- a/compose.yml +++ b/compose.yml @@ -1,6 +1,6 @@ services: magnito: - image: frourio/magnito:0.7.0 + image: frourio/magnito:0.8.0 ports: - 5000:5000 - 5001:5001 diff --git a/server/api/private/hooks.ts b/server/api/private/hooks.ts index 7f907b3..1811610 100644 --- a/server/api/private/hooks.ts +++ b/server/api/private/hooks.ts @@ -14,7 +14,7 @@ export default defineHooks(() => ({ try { await req.jwtVerify({ onlyCookie: true }); } catch (e) { - res.status(401).send(); + res.status(401).send((e as Error).message); return; } diff --git a/server/api/session/controller.ts b/server/api/session/controller.ts index a8a6353..65f1909 100644 --- a/server/api/session/controller.ts +++ b/server/api/session/controller.ts @@ -16,18 +16,21 @@ const options: CookieSerializeOptions = { sameSite: 'strict', }; -export default defineController(() => ({ +export default defineController((fastify) => ({ post: { validators: { body: z.object({ jwt: z.string() }) }, hooks: { preHandler: (req, reply, done) => { assert(req.body); - const expiresIn = 60 * 60 * 24 * 5 * 1000; + const decoded = z + .object({ payload: z.object({ exp: z.number() }).passthrough() }) + .passthrough() + .parse(fastify.jwt.decode(req.body.jwt)); reply.setCookie(COOKIE_NAME, req.body.jwt, { ...options, - expires: new Date(Date.now() + expiresIn), + expires: new Date(decoded.payload.exp * 1000), }); done(); diff --git a/server/tests/api/public.test.ts b/server/tests/api/public.test.ts index 6cf4a1f..fe538d7 100644 --- a/server/tests/api/public.test.ts +++ b/server/tests/api/public.test.ts @@ -1,3 +1,4 @@ +import { createSigner } from 'fast-jwt'; import { COOKIE_NAME } from 'service/constants'; import { expect, test } from 'vitest'; import { createUserClient, noCookieClient } from './apiClient'; @@ -24,7 +25,7 @@ test(GET(noCookieClient.health), async () => { }); test(POST(noCookieClient.session), async () => { - const jwt = 'dummy-jwt'; + const jwt = createSigner({ key: 'dummy' })({ exp: Math.floor(Date.now() / 1000) + 100 }); const res = await noCookieClient.session.post({ body: { jwt } }); expect(res.headers['set-cookie'][0].startsWith(`${COOKIE_NAME}=${jwt};`)).toBeTruthy();