import { Request, Response, NextFunction } from 'express'; import { verifyAccessToken } from '../utils/jwt'; /** * Extended Request interface with authenticated user */ export interface AuthenticatedRequest extends Request { user?: { id: string; email: string; role: string; }; } /** * Middleware to authenticate JWT access tokens * Extracts Bearer token from Authorization header, verifies it, * and attaches the decoded user to the request object */ export function authenticateToken( req: AuthenticatedRequest, res: Response, next: NextFunction ): void { const authHeader = req.headers.authorization; if (!authHeader) { res.status(401).json({ error: 'Authorization header missing' }); return; } const parts = authHeader.split(' '); if (parts.length !== 2 || parts[0] !== 'Bearer') { res.status(401).json({ error: 'Invalid authorization header format' }); return; } const token = parts[1]; try { const decoded = verifyAccessToken(token); if (!decoded) { res.status(401).json({ error: 'Invalid or expired token' }); return; } req.user = { id: decoded.id, email: decoded.email, role: decoded.role, }; next(); } catch (error) { res.status(401).json({ error: 'Invalid or expired token' }); } } /** * Middleware factory for role-based access control * Checks if the authenticated user has one of the required roles * @param roles - Array of allowed roles */ export function requireRole(...roles: string[]) { return ( req: AuthenticatedRequest, res: Response, next: NextFunction ): void => { if (!req.user) { res.status(401).json({ error: 'Authentication required' }); return; } if (!roles.includes(req.user.role)) { res.status(403).json({ error: 'Insufficient permissions' }); return; } next(); }; }