import type { Request, Response, NextFunction } from "express"; import { getAuth, clerkClient } from "@clerk/express"; export interface AuthedRequest extends Request { userId: string; userEmail: string | null; } const emailCache = new Map(); const CACHE_TTL_MS = 15 * 60 * 1000; export async function requireAuth( req: Request, res: Response, next: NextFunction, ): Promise { const auth = getAuth(req); const claimUserId = typeof auth?.sessionClaims?.["userId"] === "string" ? (auth.sessionClaims["userId"] as string) : null; const userId: string | null = claimUserId ?? auth?.userId ?? null; if (!userId) { res.status(401).json({ error: "Unauthorized" }); return; } let email: string | null = null; const cached = emailCache.get(userId); if (cached && Date.now() - cached.ts < CACHE_TTL_MS) { email = cached.email; } else { try { const user = await clerkClient.users.getUser(userId); email = user.primaryEmailAddress?.emailAddress ?? null; } catch (err) { req.log.warn({ err }, "Failed to fetch user from Clerk"); } emailCache.set(userId, { email, ts: Date.now() }); } (req as AuthedRequest).userId = userId; (req as AuthedRequest).userEmail = email; next(); }