dashboard-project-auth.ts64 lines · main
1/**
2 * Project-scoped Auth dashboard access.
3 *
4 * Platform session alone is not enough for user list / GDPR export /
5 * session revoke / roles / migration — must be admin of the target project.
6 */
7
8import type { Context } from 'hono';
9
10import { hasRoleAtLeast } from '../access.js';
11import { getProjectAccessForUser } from '../projects.js';
12import type { User } from '../../lib/auth.js';
13
14export async function requireDashboardProjectAdmin(
15 c: Context,
16 projectId: string | null | undefined,
17): Promise<{ projectId: string } | Response> {
18 const user = c.get('user') as User | null;
19 if (!user) {
20 return c.json(
21 {
22 engine: 'briven-engine',
23 code: 'unauthorized',
24 message: 'authentication required',
25 },
26 401,
27 );
28 }
29 const id = projectId?.trim() ?? '';
30 if (!id.startsWith('p_')) {
31 return c.json(
32 {
33 engine: 'briven-engine',
34 code: 'project_id_required',
35 message:
36 'projectId query/body is required (Auth admin is project-scoped)',
37 },
38 400,
39 );
40 }
41 try {
42 const access = await getProjectAccessForUser(id, user.id);
43 if (!hasRoleAtLeast(access.role, 'admin')) {
44 return c.json(
45 {
46 engine: 'briven-engine',
47 code: 'forbidden',
48 message: 'project admin role required',
49 },
50 403,
51 );
52 }
53 } catch {
54 return c.json(
55 {
56 engine: 'briven-engine',
57 code: 'forbidden',
58 message: 'no access to this project',
59 },
60 403,
61 );
62 }
63 return { projectId: id };
64}