diff --git a/frontend/src/auth/AuthContext.tsx b/frontend/src/auth/AuthContext.tsx index d6d9c51..ef3e76d 100644 --- a/frontend/src/auth/AuthContext.tsx +++ b/frontend/src/auth/AuthContext.tsx @@ -13,7 +13,7 @@ import { getAuthenticatedAuthState, getUnauthenticatedAuthState, resolveAuthStateFromMe, - validateAuthMutationResponse, + authUserFromMutation, } from './authHelpers'; interface AuthContextType extends AuthState { @@ -63,7 +63,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { }, }); - const user = validateAuthMutationResponse(response, 200); + const user = authUserFromMutation(response); if (!user) { setAuthState(getUnauthenticatedAuthState()); throw new Error('Login failed'); @@ -91,7 +91,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { }, }); - const user = validateAuthMutationResponse(response, 201); + const user = authUserFromMutation(response); if (!user) { setAuthState(getUnauthenticatedAuthState()); throw new Error('Registration failed'); @@ -113,7 +113,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { logoutMutation.mutate(undefined, { onSuccess: async () => { setAuthState(getUnauthenticatedAuthState()); - await queryClient.removeQueries({ queryKey: getGetMeQueryKey() }); + queryClient.removeQueries({ queryKey: getGetMeQueryKey() }); navigate('/login'); }, }); diff --git a/frontend/src/auth/authHelpers.test.ts b/frontend/src/auth/authHelpers.test.ts index 13fd032..99236d3 100644 --- a/frontend/src/auth/authHelpers.test.ts +++ b/frontend/src/auth/authHelpers.test.ts @@ -2,9 +2,8 @@ import { describe, expect, it } from 'vitest'; import { getCheckingAuthState, getUnauthenticatedAuthState, - normalizeAuthenticatedUser, resolveAuthStateFromMe, - validateAuthMutationResponse, + authUserFromMutation, type AuthState, } from './authHelpers'; @@ -15,20 +14,6 @@ const previousState: AuthState = { }; describe('authHelpers', () => { - it('normalizes a valid authenticated user payload', () => { - expect(normalizeAuthenticatedUser({ username: 'evan', is_admin: true })).toEqual({ - username: 'evan', - is_admin: true, - }); - }); - - it('rejects invalid authenticated user payloads', () => { - expect(normalizeAuthenticatedUser(null)).toBeNull(); - expect(normalizeAuthenticatedUser({ username: 'evan' })).toBeNull(); - expect(normalizeAuthenticatedUser({ username: 123, is_admin: true })).toBeNull(); - expect(normalizeAuthenticatedUser({ username: 'evan', is_admin: 'yes' })).toBeNull(); - }); - it('returns a checking state while preserving previous auth information', () => { expect( getCheckingAuthState({ @@ -49,6 +34,7 @@ describe('authHelpers', () => { meData: { status: 200, data: { username: 'evan', is_admin: false }, + headers: new Headers(), }, meError: undefined, meLoading: false, @@ -66,6 +52,8 @@ describe('authHelpers', () => { resolveAuthStateFromMe({ meData: { status: 401, + data: { code: 401, message: 'unauthorized' }, + headers: new Headers(), }, meError: undefined, meLoading: false, @@ -105,9 +93,7 @@ describe('authHelpers', () => { it('returns the previous state with checking disabled when there is no decisive me result', () => { expect( resolveAuthStateFromMe({ - meData: { - status: 204, - }, + meData: undefined, meError: undefined, meLoading: false, previousState: { @@ -123,35 +109,31 @@ describe('authHelpers', () => { }); }); - it('validates auth mutation responses by expected status and payload shape', () => { + it('extracts the user from successful login and register responses', () => { expect( - validateAuthMutationResponse( - { - status: 200, - data: { username: 'evan', is_admin: false }, - }, - 200 - ) + authUserFromMutation({ + status: 200, + data: { username: 'evan', is_admin: false }, + headers: new Headers(), + }) ).toEqual({ username: 'evan', is_admin: false }); expect( - validateAuthMutationResponse( - { - status: 201, - data: { username: 'evan', is_admin: false }, - }, - 200 - ) - ).toBeNull(); + authUserFromMutation({ + status: 201, + data: { username: 'evan', is_admin: true }, + headers: new Headers(), + }) + ).toEqual({ username: 'evan', is_admin: true }); + }); + it('returns null for unsuccessful auth mutation responses', () => { expect( - validateAuthMutationResponse( - { - status: 200, - data: { username: 'evan' }, - }, - 200 - ) + authUserFromMutation({ + status: 401, + data: { code: 401, message: 'unauthorized' }, + headers: new Headers(), + }) ).toBeNull(); }); }); diff --git a/frontend/src/auth/authHelpers.ts b/frontend/src/auth/authHelpers.ts index b403cea..a514ddc 100644 --- a/frontend/src/auth/authHelpers.ts +++ b/frontend/src/auth/authHelpers.ts @@ -1,7 +1,11 @@ -export interface AuthUser { - username: string; - is_admin: boolean; -} +import type { + getMeResponse, + loginResponse, + registerResponse, +} from '../generated/anthoLumeAPIV1'; +import type { LoginResponse } from '../generated/model'; + +export type AuthUser = LoginResponse; export interface AuthState { isAuthenticated: boolean; @@ -9,11 +13,6 @@ export interface AuthState { isCheckingAuth: boolean; } -interface ResponseLike { - status?: number; - data?: unknown; -} - export function getUnauthenticatedAuthState(): AuthState { return { isAuthenticated: false, @@ -38,27 +37,8 @@ export function getAuthenticatedAuthState(user: AuthUser): AuthState { }; } -export function normalizeAuthenticatedUser(value: unknown): AuthUser | null { - if (!value || typeof value !== 'object') { - return null; - } - - if (!('username' in value) || typeof value.username !== 'string') { - return null; - } - - if (!('is_admin' in value) || typeof value.is_admin !== 'boolean') { - return null; - } - - return { - username: value.username, - is_admin: value.is_admin, - }; -} - export function resolveAuthStateFromMe(params: { - meData?: ResponseLike; + meData?: getMeResponse; meError?: unknown; meLoading: boolean; previousState: AuthState; @@ -70,10 +50,7 @@ export function resolveAuthStateFromMe(params: { } if (meData?.status === 200) { - const user = normalizeAuthenticatedUser(meData.data); - if (user) { - return getAuthenticatedAuthState(user); - } + return getAuthenticatedAuthState(meData.data); } if (meError || meData?.status === 401) { @@ -86,13 +63,8 @@ export function resolveAuthStateFromMe(params: { }; } -export function validateAuthMutationResponse( - response: ResponseLike, - expectedStatus: number +export function authUserFromMutation( + response: loginResponse | registerResponse ): AuthUser | null { - if (response.status !== expectedStatus) { - return null; - } - - return normalizeAuthenticatedUser(response.data); + return response.status === 200 || response.status === 201 ? response.data : null; }