import type { Context, Next } from "jsr:@hono/hono@4"; import { getCookie } from "jsr:@hono/hono@4/cookie"; import type { AuthSdk } from "./mod.ts"; /** * Universal Hono authentication middleware for Auth-Yes. * Extracts session tokens from cookies or Authorization Bearer headers, * validates against Auth-Yes, and injects 'userId' and 'scopes' into context. */ export function createAuthMiddleware(sdk: AuthSdk) { return async (c: Context, next: Next) => { let token = getCookie(c, "session_id"); if (!token) { const authHeader = c.req.header("Authorization"); if (authHeader && authHeader.startsWith("Bearer ")) { token = authHeader.substring("Bearer ".length); } } if (!token) { return c.json({ error: "Unauthorized: Missing session token" }, 401); } try { const session = await sdk.validateSession(token); if (!session.valid || !session.uuid) { return c.json( { error: session.error || "Unauthorized: Invalid session" }, 401, ); } c.set("userId", session.uuid); c.set("scopes", session.scopes || []); await next(); } catch (_e) { return c.json({ error: "Unauthorized" }, 401); } }; } /** * RBAC Scope Guard Middleware. * Ensures the authenticated user possesses the required application scope (or global 'admin'). */ export function requireScope(requiredScope: string) { return async (c: Context, next: Next) => { const scopes: string[] = c.get("scopes") || []; if (!scopes.includes(requiredScope) && !scopes.includes("admin")) { return c.json( { error: `Forbidden: Required scope '${requiredScope}' missing.` }, 403, ); } await next(); }; }