59 lines
1.7 KiB
TypeScript
59 lines
1.7 KiB
TypeScript
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();
|
|
};
|
|
}
|