tractatus/src/middleware/auth.middleware.js
TheFlow f5c2706bcb docs(auth): add RBAC explanation to requireRole middleware
Add JSDoc comment explaining Role-Based Access Control (RBAC) middleware
functionality for the requireRole() function.

Context: Safe documentation change from stress testing cleanup. Reverted
problematic changes (.claude/settings.json, BlogPost.model.js) that violated
inst_038/inst_064.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 12:44:56 +13:00

127 lines
3 KiB
JavaScript

/**
* Authentication Middleware
* JWT-based authentication for admin routes
*/
const { verifyToken, extractTokenFromHeader } = require('../utils/jwt.util');
const { User } = require('../models');
const logger = require('../utils/logger.util');
/**
* Verify JWT token and attach user to request
*/
async function authenticateToken(req, res, next) {
try {
const token = extractTokenFromHeader(req.headers.authorization);
if (!token) {
// Log authentication attempt without token
logger.warn('Authentication attempt without token', {
ip: req.ip,
path: req.path,
method: req.method
});
return res.status(401).json({
error: 'Authentication required',
message: 'No token provided'
});
}
// Verify JWT token signature and expiration
// The verifyToken function validates the token's cryptographic signature using the
// secret key, checks that it hasn't expired, and decodes the payload containing userId
const decoded = verifyToken(token);
// Get user from database
const user = await User.findById(decoded.userId);
if (!user) {
return res.status(401).json({
error: 'Authentication failed',
message: 'User not found'
});
}
if (!user.active) {
return res.status(401).json({
error: 'Authentication failed',
message: 'User account is inactive'
});
}
// Attach user to request
req.user = user;
req.userId = user._id;
next();
} catch (error) {
logger.error('Authentication error:', error);
return res.status(401).json({
error: 'Authentication failed',
message: error.message
});
}
}
/**
* Check if user has required role
*
* Role-based access control (RBAC) middleware
* Verifies that the authenticated user possesses at least one of the required roles
* before allowing access to protected routes
*/
function requireRole(...roles) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({
error: 'Authentication required'
});
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({
error: 'Insufficient permissions',
message: `Required role: ${roles.join(' or ')}`
});
}
next();
};
}
/**
* Optional authentication (attach user if token present, continue if not)
*/
async function optionalAuth(req, res, next) {
try {
const token = extractTokenFromHeader(req.headers.authorization);
if (token) {
const decoded = verifyToken(token);
const user = await User.findById(decoded.userId);
if (user && user.active) {
req.user = user;
req.userId = user._id;
}
}
} catch (error) {
// Silently fail - authentication is optional
logger.debug('Optional auth failed:', error.message);
}
next();
}
/**
* Require admin role (convenience function)
*/
const requireAdmin = requireRole('admin');
module.exports = {
authenticateToken,
requireRole,
requireAdmin,
optionalAuth
};