two-factor.test.ts90 lines · main
1/**
2 * Two-factor + backup-code SDK contract (Sprint S1).
3 * Pins the Better Auth path names and the twoFactorRequired result shape.
4 */
5import { describe, expect, mock, test } from 'bun:test';
6
7import { createBrivenAuth } from '../index.js';
8
9function mockFetch(handler: (url: string, init?: RequestInit) => unknown) {
10 return mock(async (input: RequestInfo | URL, init?: RequestInit) => {
11 const url = typeof input === 'string' ? input : input.toString();
12 const body = handler(url, init);
13 return new Response(JSON.stringify(body), {
14 status: 200,
15 headers: { 'content-type': 'application/json' },
16 });
17 }) as unknown as typeof fetch;
18}
19
20describe('twoFactor SDK paths + results', () => {
21 test('signIn.email with twoFactorRedirect → twoFactorRequired', async () => {
22 const auth = createBrivenAuth({
23 projectId: 'p_test',
24 publicKey: 'pk_briven_auth_test',
25 fetch: mockFetch(() => ({ twoFactorRedirect: true })),
26 });
27 const result = await auth.signIn.email({ email: 'a@b.com', password: 'x' });
28 expect(result.ok).toBe(true);
29 if (result.ok) {
30 expect('twoFactorRequired' in result && result.twoFactorRequired).toBe(true);
31 }
32 });
33
34 test('twoFactor.verify posts to /two-factor/verify-totp (not /verify)', async () => {
35 let seenPath = '';
36 const auth = createBrivenAuth({
37 projectId: 'p_test',
38 publicKey: 'pk_briven_auth_test',
39 fetch: mockFetch((url) => {
40 seenPath = new URL(url).pathname;
41 return {
42 user: { id: 'u_1' },
43 session: { expiresAt: '2099-01-01T00:00:00.000Z' },
44 };
45 }),
46 });
47 const result = await auth.twoFactor.verify('123456');
48 expect(seenPath).toBe('/v1/auth-tenant/two-factor/verify-totp');
49 expect(result.ok).toBe(true);
50 if (result.ok && 'userId' in result) {
51 expect(result.userId).toBe('u_1');
52 }
53 });
54
55 test('twoFactor.verifyBackupCode posts to /two-factor/verify-backup-code', async () => {
56 let seenPath = '';
57 const auth = createBrivenAuth({
58 projectId: 'p_test',
59 publicKey: 'pk_briven_auth_test',
60 fetch: mockFetch((url) => {
61 seenPath = new URL(url).pathname;
62 return {
63 user: { id: 'u_1' },
64 session: { expiresAt: '2099-01-01T00:00:00.000Z' },
65 };
66 }),
67 });
68 const result = await auth.twoFactor.verifyBackupCode('ABCD-1234');
69 expect(seenPath).toBe('/v1/auth-tenant/two-factor/verify-backup-code');
70 expect(result.ok).toBe(true);
71 });
72
73 test('generateBackupCodes forwards password in body', async () => {
74 let body: unknown;
75 const auth = createBrivenAuth({
76 projectId: 'p_test',
77 publicKey: 'pk_briven_auth_test',
78 fetch: mockFetch((_url, init) => {
79 body = init?.body ? JSON.parse(String(init.body)) : null;
80 return { backupCodes: ['AAAA-1111', 'BBBB-2222'] };
81 }),
82 });
83 const result = await auth.twoFactor.generateBackupCodes('s3cret');
84 expect(body).toEqual({ password: 's3cret' });
85 expect(result.ok).toBe(true);
86 if (result.ok) {
87 expect(result.codes).toHaveLength(2);
88 }
89 });
90});