auth-team.ts40 lines · main
1import type { MiddlewareHandler } from 'hono';
2import { ForbiddenError } from '@briven/shared';
3import { hasRoleAtLeast } from '../services/access.js';
4import { getAuthTeamRole } from '../services/auth-team-seats.js';
5import type { MemberRole } from '../db/schema.js';
6import type { Session, User } from './session.js';
7
8/**
9 * Auth-team access gate for `/v1/projects/:id/auth/*` routes.
10 *
11 * Must run AFTER `requireProjectAuth()` (which populates `projectRole`).
12 * If the user already has project-level admin/owner access, pass through.
13 * Otherwise, check the `project_auth_team_members` table — an auth team
14 * admin is treated as project admin for the remainder of the request.
15 *
16 * Viewer-tier auth team members are NOT elevated by this middleware;
17 * routes that want to allow viewers should skip this gate.
18 */
19export const requireAuthTeamAdmin = (): MiddlewareHandler => async (c, next) => {
20 const role = c.get('projectRole') as MemberRole | null | undefined;
21 if (role && hasRoleAtLeast(role, 'admin')) {
22 return next();
23 }
24
25 const user = c.get('user') as User | null;
26 const projectId = c.req.param('id');
27 if (user && projectId) {
28 const teamRole = await getAuthTeamRole(projectId, user.id);
29 if (teamRole === 'admin') {
30 // Elevate the request context so downstream `requireProjectRole('admin')`
31 // sees an effective admin role.
32 c.set('projectRole', 'admin');
33 return next();
34 }
35 }
36
37 throw new ForbiddenError('requires auth team admin access');
38};
39
40export type { Session, User };