diff --git a/src/workspaces/hooks/src/useAuth/useAuth.ts b/src/workspaces/hooks/src/useAuth/useAuth.ts index b8aa8b95..af975267 100644 --- a/src/workspaces/hooks/src/useAuth/useAuth.ts +++ b/src/workspaces/hooks/src/useAuth/useAuth.ts @@ -7,6 +7,16 @@ import { usePasskeys } from './usePasskeys'; type UseAuthProps = { authUrl?: string; apiUrl?: string } | undefined; export type UserWithToken = User & { token: string }; +// POST /auth/signin — `token` is withheld when the account has passkeys, which routes the caller +// through the passkey challenge instead. +type SigninResponse = { + token?: string; + user: User & { passkeys: number }; +}; + +// POST /auth/change-password — a fresh token, since changing the password invalidates the old one. +type TokenResponse = { token?: string }; + export const useAuth = (props: UseAuthProps = {}) => { const { authUrl = '/api/auth', apiUrl = '/api' } = props; const queryClient = useQueryClient(); @@ -43,7 +53,7 @@ export const useAuth = (props: UseAuthProps = {}) => { const signin = async ({ email, password }: { email: string; password: string }) => { localStorage.removeItem('BEARER_TOKEN'); - const data = await authClient.post('/signin', { email, password }); + const data = await authClient.post('/signin', { email, password }); const { user, token } = data; @@ -52,9 +62,13 @@ export const useAuth = (props: UseAuthProps = {}) => { return; } - localStorage.setItem('BEARER_TOKEN', data.token); + // The server only withholds the token for the passkey flow handled above, so this should not + // happen — but storing `undefined` would persist the literal string "undefined" as the token. + if (!token) return; + + localStorage.setItem('BEARER_TOKEN', token); queryClient.invalidateQueries({ queryKey: ['CURRENT_USER'] }); - return data.token; + return token; }; const signout = async () => { @@ -81,7 +95,7 @@ export const useAuth = (props: UseAuthProps = {}) => { }; const changePassword = async (payload: ChangePasswordPayload) => { - const data = await authClient.post('/change-password', payload); + const data = await authClient.post('/change-password', payload); if (data.token) { localStorage.setItem('BEARER_TOKEN', data.token); queryClient.invalidateQueries({ queryKey: ['CURRENT_USER'] }); diff --git a/src/workspaces/hooks/src/useClient.ts b/src/workspaces/hooks/src/useClient.ts index d32ef489..ddd18f8e 100644 --- a/src/workspaces/hooks/src/useClient.ts +++ b/src/workspaces/hooks/src/useClient.ts @@ -68,7 +68,7 @@ export const get = async (uri: string, baseUrl = '') => { const res = await fetch(theUrl, { headers }); await validateResponse(res); const data = await res.json(); - return data as T | any; + return data as T; }; export const getBlob = async (uri: string, baseUrl = '') => { @@ -101,7 +101,7 @@ export const post = async (uri: string, payload?: any, baseUrl = '') => { }); await validateResponse(res); const data = await res.json(); - return data as T | any; + return data as T; }; export const put = async (uri: string, payload?: any, baseUrl = '') => { @@ -120,7 +120,7 @@ export const put = async (uri: string, payload?: any, baseUrl = '') => { }); await validateResponse(res); const data = await res.json(); - return data as T | any; + return data as T; }; export const patch = async (uri: string, payload?: any, baseUrl = '') => { @@ -133,7 +133,7 @@ export const patch = async (uri: string, payload?: any, baseUrl = '') => { }); await validateResponse(res); const data = await res.json(); - return data as T | any; + return data as T; }; export const DELETE = async (uri: string, payload?: any, baseUrl = '') => { @@ -146,7 +146,7 @@ export const DELETE = async (uri: string, payload?: any, baseUrl = '') => { }); await validateResponse(res); const data = await res.json(); - return data as T | any; + return data as T; }; const validateResponse = async (res: Response) => {