67 lines
1.9 KiB
TypeScript
67 lines
1.9 KiB
TypeScript
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();
|
|
}
|