diff --git a/apps/web/src/stores/auth-store.test.ts b/apps/web/src/stores/auth-store.test.ts index 4ac66c5c29e..8acb03a33e0 100644 --- a/apps/web/src/stores/auth-store.test.ts +++ b/apps/web/src/stores/auth-store.test.ts @@ -12,6 +12,13 @@ let getSessionFailFirstCall = false; const syncOnboardingUserMock = mock((_userId: string | null) => {}); const clearOrganizationMock = mock(() => {}); const logoutMock = mock(async () => {}); +const deleteBiometricTokenMock = mock(async () => {}); + +let mockIsNativePlatform = false; +let mockIsBiometricEnabled = false; +let mockBiometricToken: string | null = null; +const installSessionCookiesMock = mock((_token: string) => {}); +const retrieveBiometricTokenMock = mock(async () => mockBiometricToken); mock.module("@/lib/auth/allauth-client.js", () => ({ getSession: async () => { @@ -27,18 +34,13 @@ mock.module("@/lib/auth/allauth-client.js", () => ({ logout: logoutMock, })); -let mockIsNativePlatform = false; -let mockIsBiometricEnabled = false; -let mockBiometricToken: string | null = null; -const installSessionCookiesMock = mock((_token: string) => {}); -const retrieveBiometricTokenMock = mock(async () => mockBiometricToken); - mock.module("@/runtime/native-auth.js", () => ({ isNativePlatform: () => mockIsNativePlatform, installSessionCookies: installSessionCookiesMock, })); mock.module("@/runtime/native-biometric.js", () => ({ + deleteBiometricToken: deleteBiometricTokenMock, isBiometricEnabled: () => mockIsBiometricEnabled, retrieveBiometricToken: retrieveBiometricTokenMock, })); @@ -79,6 +81,8 @@ beforeEach(() => { syncOnboardingUserMock.mockClear(); clearOrganizationMock.mockClear(); logoutMock.mockClear(); +<<<<<<< HEAD + deleteBiometricTokenMock.mockClear(); installSessionCookiesMock.mockClear(); retrieveBiometricTokenMock.mockClear(); resetAuthStore(); @@ -113,6 +117,14 @@ describe("auth store onboarding flag reconciliation", () => { }); }); +describe("biometric cleanup on logout", () => { + test("logout clears biometric token", async () => { + await useAuthStore.getState().logout(); + + expect(deleteBiometricTokenMock).toHaveBeenCalled(); + }); +}); + describe("biometric session recovery", () => { test("initSession falls through to biometric recovery on native when session probe fails", async () => { mockIsNativePlatform = true; diff --git a/apps/web/src/stores/auth-store.ts b/apps/web/src/stores/auth-store.ts index 14088f50fc9..306d242d99c 100644 --- a/apps/web/src/stores/auth-store.ts +++ b/apps/web/src/stores/auth-store.ts @@ -19,6 +19,7 @@ import { getSession, logout as allauthLogout, } from "@/lib/auth/allauth-client.js"; +import { deleteBiometricToken } from "@/runtime/native-biometric.js"; import { syncOnboardingUser } from "@/domains/onboarding/prefs.js"; import { clearOrganization } from "@/stores/organization-store.js"; import { useEventBusStore } from "@/stores/event-bus-store.js"; @@ -155,6 +156,7 @@ const useAuthStoreBase = create()((set) => ({ try { await allauthLogout(); } finally { + void deleteBiometricToken(); syncUserScopedState(null); set({ isLoggedIn: false, user: null }); broadcastAuthChange();