session.test.ts94 lines · main
1// apps/api/src/middleware/session.test.ts
2//
3// Env vars must be set BEFORE any module that reads them is imported.
4// auth.ts calls getDb() at module evaluation, so we have to mutate
5// process.env before any static import that pulls auth.ts in. To keep the
6// invariant when this file is loaded alongside siblings (which may have
7// already cached session.ts), all framework imports live inside dynamic
8// imports below.
9
10const ORIGINAL_SECRET = process.env.BRIVEN_BETTER_AUTH_SECRET;
11const ORIGINAL_DB_URL = process.env.BRIVEN_DATABASE_URL;
12process.env.BRIVEN_BETTER_AUTH_SECRET = ORIGINAL_SECRET ?? 'a'.repeat(32);
13// auth.ts evaluates getDb() at module load — provide a syntactically valid
14// URL so the import doesn't throw. The actual postgres connection is lazy
15// (only opened when a query runs), and the bearer branch catches errors.
16process.env.BRIVEN_DATABASE_URL = ORIGINAL_DB_URL ?? 'postgres://test:test@127.0.0.1:5/test';
17
18import { describe, expect, it, afterAll } from 'bun:test';
19import type { AppEnv } from '../types/app-env.js';
20
21describe('requireAuth — Bearer JWT', () => {
22 it('attaches user from a valid cli token', async () => {
23 const { Hono } = await import('hono');
24 const { signCliToken } = await import('../lib/cli-jwt.js');
25 const { requireAuth } = await import('./session.js');
26 const app = new Hono<AppEnv>();
27 app.use('*', requireAuth());
28 app.get('/who', (c) => c.json({ id: (c.get('user') as { id?: string } | undefined)?.id }));
29
30 const token = await signCliToken('u_session_test');
31 const res = await app.request('/who', {
32 headers: { authorization: `Bearer ${token}` },
33 });
34 // Either 200 (user found) or 401 (cli-token user not in DB) is acceptable.
35 // The point of this test is to prove the BEARER PATH ran — not that the DB has the user.
36 expect([200, 401]).toContain(res.status);
37 const body = (await res.json()) as { id?: string; code?: string; message?: string };
38 if (res.status === 200) {
39 expect(body.id).toBe('u_session_test');
40 } else {
41 expect(body.code).toBe('unauthorized');
42 // The message must come from the cli-token branch, not the cookie branch.
43 expect(body.message).toMatch(/cli token/i);
44 }
45 });
46
47 it('rejects an expired or malformed bearer', async () => {
48 const { Hono } = await import('hono');
49 const { requireAuth } = await import('./session.js');
50 const app = new Hono<AppEnv>();
51 app.use('*', requireAuth());
52 app.get('/who', (c) => c.json({}));
53 const res = await app.request('/who', {
54 headers: { authorization: 'Bearer not.a.jwt' },
55 });
56 expect(res.status).toBe(401);
57 const body = (await res.json()) as { code: string; message: string };
58 expect(body.message).toMatch(/invalid cli token/i);
59 });
60
61 it('lets SCIM paths through for scim_briven tokens (directory sync)', async () => {
62 const { Hono } = await import('hono');
63 const { requireAuth } = await import('./session.js');
64 const app = new Hono<AppEnv>();
65 app.use('*', requireAuth());
66 app.get('/v1/projects/:id/scim/v2/Users', (c) => c.json({ ok: true }));
67 const res = await app.request(
68 '/v1/projects/p_test/scim/v2/Users',
69 { headers: { authorization: 'Bearer scim_briven_fake_token' } },
70 );
71 expect(res.status).toBe(200);
72 const body = (await res.json()) as { ok: boolean };
73 expect(body.ok).toBe(true);
74 });
75
76 it('lets /scim/v2 paths through without a session (handler enforces token)', async () => {
77 const { Hono } = await import('hono');
78 const { requireAuth } = await import('./session.js');
79 const app = new Hono<AppEnv>();
80 app.use('*', requireAuth());
81 app.get('/v1/projects/:id/scim/v2/ServiceProviderConfig', (c) =>
82 c.json({ scim: true }),
83 );
84 const res = await app.request('/v1/projects/p_test/scim/v2/ServiceProviderConfig');
85 expect(res.status).toBe(200);
86 });
87});
88
89afterAll(() => {
90 if (ORIGINAL_SECRET === undefined) delete process.env.BRIVEN_BETTER_AUTH_SECRET;
91 else process.env.BRIVEN_BETTER_AUTH_SECRET = ORIGINAL_SECRET;
92 if (ORIGINAL_DB_URL === undefined) delete process.env.BRIVEN_DATABASE_URL;
93 else process.env.BRIVEN_DATABASE_URL = ORIGINAL_DB_URL;
94});