44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
|
|
import { Response, NextFunction } from "express";
|
||
|
|
import jwt from "jsonwebtoken";
|
||
|
|
import { AuthPayload, AuthenticatedRequest } from "../types/index.js";
|
||
|
|
import { AppError } from "./errorHandler.js";
|
||
|
|
|
||
|
|
export function requireAuth(
|
||
|
|
req: AuthenticatedRequest,
|
||
|
|
_res: Response,
|
||
|
|
next: NextFunction
|
||
|
|
): void {
|
||
|
|
const authHeader = req.headers.authorization;
|
||
|
|
if (!authHeader?.startsWith("Bearer ")) {
|
||
|
|
return next(new AppError(401, "UNAUTHORIZED", "Missing or invalid token"));
|
||
|
|
}
|
||
|
|
|
||
|
|
const token = authHeader.slice(7);
|
||
|
|
const secret = process.env.JWT_SECRET;
|
||
|
|
if (!secret) {
|
||
|
|
return next(new AppError(500, "CONFIG_ERROR", "JWT secret not configured"));
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const payload = jwt.verify(token, secret) as AuthPayload;
|
||
|
|
req.auth = payload;
|
||
|
|
next();
|
||
|
|
} catch {
|
||
|
|
next(new AppError(401, "UNAUTHORIZED", "Invalid or expired token"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function requireRole(...roles: string[]) {
|
||
|
|
return (req: AuthenticatedRequest, _res: Response, next: NextFunction) => {
|
||
|
|
if (!req.auth) {
|
||
|
|
return next(new AppError(401, "UNAUTHORIZED", "Not authenticated"));
|
||
|
|
}
|
||
|
|
if (!roles.includes(req.auth.roleName)) {
|
||
|
|
return next(
|
||
|
|
new AppError(403, "FORBIDDEN", "Insufficient permissions")
|
||
|
|
);
|
||
|
|
}
|
||
|
|
next();
|
||
|
|
};
|
||
|
|
}
|