Skip to main content

How to Implement Role-Based Access Control

Implement RBAC by modeling permissions into roles, carrying roles in token claims, enforcing them through a reusable middleware guard, and centralizing the policy. Includes 401-vs-403 distinction and testing.

Difficulty
Intermediate
Duration
45 minutes
Steps
5

What and why

Authentication answers who you are; authorization answers what you may do. Role-Based Access Control (RBAC) groups permissions into roles and assigns roles to users, so access rules stay manageable as the system grows. Centralizing the checks prevents inconsistent, ad-hoc rules scattered across handlers.

Prerequisites

  • An API with authentication in place.
  • A user store that records roles.
  • Familiarity with middleware.

Steps

1. Model roles and permissions

Define permissions as fine-grained verbs on resources, then compose them into roles:

const permissions = { admin: ['article:*'], editor: ['article:read', 'article:write'], viewer: ['article:read'] };

Granting permissions through roles, rather than to individual users, keeps assignment simple.

2. Attach roles to the identity

Carry roles in the verified token claims (for example a roles claim in a JWT or an OIDC token) so each request already knows the caller's roles without an extra lookup.

3. Enforce with middleware

Write a reusable guard that checks a required permission:

const require = (perm) => (req, res, next) => {
  const granted = req.user.roles.flatMap(r => permissions[r] || []);
  const ok = granted.some(p => p === perm || p === perm.split(':')[0] + ':*');
  return ok ? next() : res.status(403).json({ error: 'forbidden' });
};
app.post('/v1/articles', require('article:write'), createArticle);

Return 403 for an authenticated user lacking permission, distinct from 401 for no identity.

4. Centralize the policy

Keep the permission map and the guard in one module so every route uses the same logic. For complex rules (ownership, attributes), consider a policy engine such as OPA so policy lives outside scattered code.

5. Test authorization rules

Write tests for each role against each protected route, including the negative cases. Authorization bugs are usually missing checks, so test that forbidden actions actually return 403.

Verification

  • An admin can perform all actions.
  • A viewer is denied write actions with 403.
  • An unauthenticated request returns 401, not 403.

Next Steps

Add resource-level checks for ownership (a user may edit only their own records), audit-log authorization decisions, and move toward attribute-based access control if role explosion becomes a problem.

Prerequisites

  • An authenticated API
  • A user store with roles
  • Basic middleware knowledge

Steps

  • 1
    Model roles and permissions
  • 2
    Attach roles to the identity
  • 3
    Enforce with middleware
  • 4
    Centralize the policy
  • 5
    Test authorization rules