/**
* @file Authentication and authorization middleware for Express.
* @module middleware/authMiddleware
* @requires jsonwebtoken
* @requires ../models/userModel
*/
const jwt = require("jsonwebtoken");
const User = require("../models/userModel");
/**
* Middleware to protect routes by verifying a JWT token.
*
* - Looks for a token in the `Authorization` header in the format: `Bearer <token>`.
* - Verifies the token and decodes the user ID.
* - Attaches the user (minus password) to `req.user`.
*
* @async
* @function protect
* @param {Object} req - Express request object. Expects an `Authorization` header.
* @param {Object} res - Express response object.
* @param {Function} next - Express next middleware function.
* @returns {Promise<void>} Proceeds to next middleware if authorized, otherwise responds with 401 Unauthorized.
*/
const protect = async (req, res, next) => {
let token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith("Bearer")
) {
try {
// Get token from header
token = req.headers.authorization.split(" ")[1];
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Get user from the token payload (ID)
req.user = await User.findById(decoded.id).select("-password");
if (!req.user) {
return res
.status(401)
.json({ message: "Not authorized, user not found" });
}
next();
} catch (error) {
console.error(error);
res.status(401).json({ message: "Not authorized, token failed" });
}
}
if (!token) {
res.status(401).json({ message: "Not authorized, no token" });
}
};
/**
* Middleware to restrict access to admin-only routes.
*
* - Must be used **after** the `protect` middleware.
* - Checks if `req.user.role` is `"admin"`.
*
* @function admin
* @param {Object} req - Express request object. Requires `req.user` to be set by `protect`.
* @param {Object} res - Express response object.
* @param {Function} next - Express next middleware function.
* @returns {void} Proceeds to next middleware if user is admin, otherwise responds with 403 Forbidden.
*/
const admin = (req, res, next) => {
if (req.user && req.user.role === "admin") {
next();
} else {
res.status(403).json({ message: "Not authorized as an admin" });
}
};
module.exports = { protect, admin };