import { Request, Response, NextFunction } from "express"; import logger from "../utils/logger"; export interface AuthenticatedUser { id: string; email: string | null; nickname: string; isActive: boolean; linkedProviders: string[]; } export interface AuthenticatedRequest extends Request { user: AuthenticatedUser; } /** * Middleware d'authentification — Token Introspection via SuperOAuth * * Valide le Bearer token auprès de SuperOAuth (POST /api/auth/token/validate). * Aucun secret JWT partagé — SuperOAuth garde le contrôle total. * * Flow : * 1. Extraire le Bearer token du header Authorization * 2. Appeler SuperOAuth /api/auth/token/validate * 3. Si valid → attacher req.user et continuer * 4. Sinon → 401 */ export const requireAuth = async ( req: Request, res: Response, next: NextFunction ): Promise => { const token = req.headers.authorization?.split(" ")[1] ?? (req.cookies as Record)?.od_token; if (!token) { res.status(401).json({ success: false, error: "UNAUTHORIZED", message: "Access token required" }); return; } const superOAuthUrl = process.env.SUPER_OAUTH_URL; if (!superOAuthUrl) { logger.error("SUPER_OAUTH_URL not configured"); res.status(500).json({ success: false, error: "INTERNAL_ERROR", message: "Auth service not configured" }); return; } try { const response = await fetch(`${superOAuthUrl}/api/v1/auth/token/validate`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token }), }); const data = await response.json() as { success: boolean; data?: { valid: boolean; user?: AuthenticatedUser }; error?: string; }; if (!response.ok || !data.data?.valid || !data.data.user) { res.status(401).json({ success: false, error: data.error ?? "INVALID_TOKEN", message: "Invalid or expired token" }); return; } if (!data.data.user.isActive) { res.status(401).json({ success: false, error: "ACCOUNT_DISABLED", message: "Account is disabled" }); return; } (req as AuthenticatedRequest).user = data.data.user; next(); } catch (err) { logger.error("requireAuth — auth service unreachable", { err }); res.status(500).json({ success: false, error: "AUTH_SERVICE_UNAVAILABLE", message: "Authentication service unreachable" }); } };