import { expect, test } from "bun:test"; import { createAuthEngine } from "../src/engine.ts"; import { MemoryAuthStore } from "../src/stores/memory.ts"; const profile = { id: "google-user", email: "google@example.test", raw: { email_verified: true } }; function setup(providers?: string[]) { const store = new MemoryAuthStore(); const engine = createAuthEngine({ store, secret: "oauth-device-policy-test-at-least-32-characters", requireVerifiedEmail: true, requireTrustedDeviceVerification: true, verifiedOAuthDeviceProviders: providers, isOAuthEmailVerified: (_provider, value) => value.raw.email_verified === true, }); return { engine, store }; } test("explicit verified Google policy satisfies the device check without trusting future password logins", async () => { const { engine } = setup(["google"]); const result = await engine.loginWithOAuth("google", profile, undefined, { fingerprint: "new-browser", }); expect(result.ok).toBe(true); expect(result.session).toBeDefined(); expect(await engine.listTrustedDevices(result.user!.id)).toHaveLength(0); }); test("device verification remains the default and applies to other providers", async () => { expect((await setup().engine.loginWithOAuth("google", profile)).code).toBe("mfa-required"); expect((await setup(["google"]).engine.loginWithOAuth("other", profile)).code).toBe( "mfa-required", ); }); test("unverified provider emails cannot satisfy verification", async () => { const { engine } = setup(["google"]); const result = await engine.loginWithOAuth("google", { ...profile, raw: { email_verified: false }, }); expect(result.ok).toBe(false); expect(result.session).toBeUndefined(); }); test("explicit account MFA remains required after verified Google sign-in", async () => { const { engine } = setup(["google"]); const first = await engine.loginWithOAuth("google", profile); await engine.generateRecoveryCodes(first.user!.id); const result = await engine.loginWithOAuth("google", profile); expect(result.code).toBe("mfa-required"); expect(result.session).toBeUndefined(); expect(result.requires?.mfa).toContain("recovery-code"); });