import type { Request, Response, NextFunction } from "express"; import jwt from "jsonwebtoken"; import type { AuthenticatedUser, Role } from "@fleetforge/shared"; const JWT_SECRET = process.env.JWT_SECRET || "dev-secret"; const ROLE_HIERARCHY: Record = { owner: 4, admin: 3, operator: 2, read_only: 1, }; export function generateToken(user: AuthenticatedUser): string { return jwt.sign( { userId: user.userId, organizationId: user.organizationId, role: user.role, email: user.email, }, JWT_SECRET, { expiresIn: (process.env.JWT_EXPIRES_IN || "24h") as any } ); } export function verifyToken(token: string): AuthenticatedUser { return jwt.verify(token, JWT_SECRET) as AuthenticatedUser; } export function authenticate(req: Request, res: Response, next: NextFunction) { const authHeader = req.headers.authorization; if (!authHeader?.startsWith("Bearer ")) { res.status(401).json({ success: false, error: { code: "UNAUTHORIZED", message: "Missing or invalid token" }, }); return; } try { const token = authHeader.substring(7); const user = verifyToken(token); (req as any).user = user; next(); } catch { res.status(401).json({ success: false, error: { code: "UNAUTHORIZED", message: "Invalid or expired token" }, }); } } export function authorize(...allowedRoles: Role[]) { return (req: Request, res: Response, next: NextFunction) => { const user = (req as any).user as AuthenticatedUser; if (!user) { res.status(401).json({ success: false, error: { code: "UNAUTHORIZED", message: "Not authenticated" }, }); return; } if (allowedRoles.length > 0) { const hasRole = allowedRoles.some( (role) => ROLE_HIERARCHY[user.role] >= ROLE_HIERARCHY[role] ); if (!hasRole) { res.status(403).json({ success: false, error: { code: "FORBIDDEN", message: "Insufficient permissions" }, }); return; } } next(); }; }