100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Node.js & Express Backend
30 minintermediate

Role-Based Access Control (RBAC)

Role-Based Access Control (RBAC)

Authentication answers 'who are you?' — RBAC answers 'what are you allowed to do?' Role-Based Access Control assigns permissions to roles, and roles to users. A user inherits all permissions of their role(s). This is simpler to manage than per-user permission lists and scales well as your application grows from dozens to thousands of users. In Express, RBAC is typically implemented as a middleware chain that runs after JWT authentication.

Analogy🏏Cricket
Think of it like cricket: The BCCI has different clearance levels: players, umpires, selectors, commentators, and administrators. A player can access the dressing room but not the selection committee meeting. An umpire can access the field and the replay room but not the broadcast truck. An administrator can access everything. Nobody's permissions are listed individually — they inherit them from their role. Rohit Sharma's role is 'captain', which grants dressing-room access, team sheet editing rights, and toss authority, but not board-level financial decisions.

Defining Roles and Permissions

A clean RBAC implementation separates three concerns: the role definitions (what roles exist), the permission map (what each role can do), and the enforcement middleware (which routes require which permissions). This separation lets you update permissions without touching route code and makes permission audits straightforward.

javascript
// config/roles.js
const ROLES = {
  USER: 'user',
  EDITOR: 'editor',
  ADMIN: 'admin'
};

const PERMISSIONS = {
  [ROLES.USER]: [
    'read:products',
    'read:own-orders',
    'write:own-profile'
  ],
  [ROLES.EDITOR]: [
    'read:products',
    'write:products',
    'read:orders',
    'read:own-orders',
    'write:own-profile'
  ],
  [ROLES.ADMIN]: [
    'read:products',  'write:products',  'delete:products',
    'read:orders',    'write:orders',    'delete:orders',
    'read:users',     'write:users',     'delete:users',
    'read:own-orders','write:own-profile'
  ]
};

function hasPermission(role, permission) {
  return PERMISSIONS[role]?.includes(permission) ?? false;
}

module.exports = { ROLES, PERMISSIONS, hasPermission };
Analogy🏏Cricket
Think of it like cricket: Think of the PERMISSIONS object as the BCCI's official access matrix, laminated and posted at every gate. Gate staff don't memorise each player's individual rights — they check the matrix: 'what role does this badge show? What does that role allow here?' The gate check is the authorize middleware; the matrix is the PERMISSIONS config.

The authorize Middleware

The authorize middleware factory takes a required permission as an argument and returns a middleware function. It runs after the authenticate middleware (which sets req.user), reads the user's role from the JWT payload, and checks it against the permission map. If the check passes, it calls next(); otherwise it returns 403 Forbidden.

javascript
// middleware/authorize.js
const { hasPermission } = require('../config/roles');

function authorize(permission) {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(401).json({ error: 'Unauthenticated' });
    }
    if (!hasPermission(req.user.role, permission)) {
      return res.status(403).json({
        error: 'Forbidden',
        required: permission,
        yourRole: req.user.role
      });
    }
    next();
  };
}

module.exports = authorize;

// Using it in routes
const authenticate = require('../middleware/authenticate');
const authorize    = require('../middleware/authorize');

router.get('/products',    authenticate, authorize('read:products'),   listProducts);
router.post('/products',   authenticate, authorize('write:products'),  createProduct);
router.delete('/products/:id', authenticate, authorize('delete:products'), deleteProduct);
router.get('/users',       authenticate, authorize('read:users'),      listUsers);
Analogy🏏Cricket
Think of it like cricket: The authorize middleware is the dressing-room steward. First, the authentication guard at the main gate checks your player ID (authenticate). Then the dressing-room steward checks your specific clearance card for this area — 'do you have write:products access?' If not, you get a polite but firm 403 — not today, even if you are a legitimate player.
Lesson 23 of 36
0% complete