Skip to content

The RBAC Middleware

In the previous lesson, we implemented the requireAuth middleware, which explicitly validates incoming session cookies and blocks anonymous access to the admin dashboard.

Role-Based Authorization introduces a “Two-Layer” defensive architecture, seamlessly augmenting our existing security perimeter:

  1. Authentication Layer: Are you logged into the application? (Handled by requireAuth).
  2. Authorization Layer: Do your capabilities align with the requested action? (Handled by our new requireRole).

To apply this correctly, we dynamically construct completely reusable, centralized middleware. This generic function accepts an array of allowed roles and fundamentally evaluates the incoming req.user against that array before passing control to the final controller.

middleware/auth.js
// Layer 1: The standard Authentication Guard
function requireAuth(req, res, next) {
if (req.isAuthenticated?.() && req.user) return next();
return res.redirect("/admin/login");
}
// Layer 2: The dynamic Role Authorization Guard
function requireRole(...allowedRoles) {
return (req, res, next) => {
// Failsafe: If no user context exists, bounce them
if (!req.user) return res.redirect("/admin/login");
// Evaluate if the user's role string actively matches the allowed array
if (allowedRoles.includes(req.user.role)) {
return next();
}
// Explicit Authorization Failure
return res
.status(403)
.send("Access Denied: You do not possess the required capabilities.");
};
}
module.exports = { requireAuth, requireRole };

Professor Solo: The incredible power of requireRole(...allowedRoles) is the spread operator. It allows us to dynamically configure the middleware right at the router level by passing in an array of strings (e.g. requireRole("ADMIN", "MODERATOR")), creating a modular, reusable security barrier.

Once this centralized function acts as the gatekeeper, we can secure every administrative endpoint. Checking the role in one centralized place drastically reduces security breaches.

T.A. Watts Note: Checking req.user.role natively inside specific individual route handlers creates sprawling authorization “spaghetti”. Consistently prioritize deploying your centralized generic middleware over every administrative route. It is vastly safer to secure an endpoint centrally than scattering if(role === 'ADMIN') throughout 50 controllers.

Neo-Retro isometric conceptual diagram illustrating a Two-Layer security architecture with Authentication and Authorization shields

Fig 1: Layer 1 Authentication (Passport) vs. Layer 2 Authorization (RBAC)


The bouncers are ready. Let’s tell them which Express router doors to guard.