auth-yes/sdk/hono.ts

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();
};
}