auth-yes/server/auth-session.ts

105 lines
2.7 KiB
TypeScript

import type { Context } from "jsr:@hono/hono@4";
import {
getClientIp,
getCookieDomain,
isIpAllowed,
isPathBypassed,
isSafeRedirectUrl,
} from "./forward_auth.ts";
import {
type AppRecord,
type AuthenticatedUser,
extractAllSessionIds,
getAppByHost,
getAuthenticatedUser,
getUserGrant,
isGlobalAdmin,
} from "./session_resolver.ts";
// Re-export for backward compatibility
export {
type AppRecord,
type AuthenticatedUser,
extractAllSessionIds,
getAppByHost,
getAuthenticatedUser,
getClientIp,
getCookieDomain,
getUserGrant,
isGlobalAdmin,
isIpAllowed,
isPathBypassed,
isSafeRedirectUrl,
};
/**
* Evaluates if the current user's capabilities satisfy the required scope.
* If !auth.isAgent, primary sessions inherit full capabilities (returns true).
* If auth.isAgent, checks if customScopes contains the requiredScope or '*'.
*/
export function hasScope(
auth: AuthenticatedUser,
requiredScope: string,
): boolean {
if (!auth.isAgent) return true;
if (!Array.isArray(auth.customScopes)) return false;
return auth.customScopes.includes("*") ||
auth.customScopes.includes(requiredScope);
}
/**
* Helper to check if the session itself is authorized as an admin.
*/
export async function isSessionAdmin(
auth: AuthenticatedUser,
): Promise<boolean> {
const globalAdmin = await isGlobalAdmin(auth.userId);
if (!globalAdmin) return false;
if (!auth.isAgent) return true;
return Array.isArray(auth.customScopes) && auth.customScopes.includes("*");
}
/**
* Hono Middleware: Blocks access if the session is a delegated agent session.
*/
export async function requirePrimarySession(
c: Context,
next: () => Promise<void>,
) {
const auth = await getAuthenticatedUser(c);
if (!auth) return c.json({ error: "Unauthorized" }, 401);
if (auth.isAgent) {
return c.json({ error: "Forbidden: Primary session required" }, 403);
}
await next();
}
/**
* Hono Middleware Factory: Requires a specific scope.
*/
export function requireScope(scope: string) {
return async (c: Context, next: () => Promise<void>) => {
const auth = await getAuthenticatedUser(c);
if (!auth) return c.json({ error: "Unauthorized" }, 401);
if (!hasScope(auth, scope)) {
return c.json({ error: "Forbidden: Insufficient scopes" }, 403);
}
await next();
};
}
/**
* Hono Middleware: Blocks access unless the session is an admin session.
*/
export async function requireAdmin(c: Context, next: () => Promise<void>) {
const auth = await getAuthenticatedUser(c);
if (!auth) return c.json({ error: "Unauthorized" }, 401);
const isAdmin = await isSessionAdmin(auth);
if (!isAdmin) {
return c.json({ error: "Forbidden: Global admin access required" }, 403);
}
await next();
}