import { eq } from "drizzle-orm"; import type { Context, Next } from "hono"; import { users } from "../../db/schema.ts"; import { getOrCreateUser, verifyApiKey } from "../services/auth.service"; import { getOrCreateUncategorized } from "../services/category.service"; import { verifyAccessToken } from "../services/oauth.service"; export async function requireAuth(c: Context, next: Next) { const db = c.get("db"); // Check API key first const apiKey = c.req.header("X-API-Key"); if (apiKey) { const result = await verifyApiKey(db, apiKey); if (result) { c.set("userId", result.userId); return next(); } return c.json({ error: "Invalid API key" }, 401); } // Check OAuth Bearer token const authHeader = c.req.header("Authorization"); if (authHeader?.startsWith("Bearer ")) { const token = authHeader.slice(7); const result = await verifyAccessToken(db, token); if (result) { c.set("userId", result.userId); return next(); } return c.json({ error: "Invalid or expired token" }, 401); } // Check OIDC session (browser users via Logto) try { const { getAuth } = await import("@hono/oidc-auth"); const auth = await getAuth(c); if (auth?.sub) { const user = await getOrCreateUser(db, auth.sub); await getOrCreateUncategorized(db, user.id); c.set("userId", user.id); return next(); } } catch (err) { console.error("[auth] OIDC auth failed:", err); // OIDC not configured or session invalid — fall through } return c.json({ error: "Authentication required" }, 401); } export async function requireAdmin(c: Context, next: Next) { const db = c.get("db"); const userId = c.get("userId"); if (!userId) { return c.json({ error: "Authentication required" }, 401); } const [user] = await db .select({ isAdmin: users.isAdmin }) .from(users) .where(eq(users.id, userId)); if (!user?.isAdmin) { return c.json({ error: "Forbidden" }, 403); } return next(); }