Facebook Pixel

Role-Based Access Control (RBAC) in Node.js

RBAC is the common way to handle permissions. Here is how to implement it in Node.js.

Role-Based Access Control (RBAC) in Node.js

RBAC is the common way to handle permissions. Users have roles (user, admin, moderator); roles have permissions. Here is how to implement it in Node.js.

The Model

userSchema.add({ role: { type: String, enum: ['user', 'admin', 'moderator'], default: 'user' } });

The Auth Middleware

const auth = (req, res, next) => {
  const token = req.cookies.token;
  if (!token) return res.status(401).json({ error: 'Not authenticated' });
  try {
    req.user = jwt.verify(token, process.env.JWT_SECRET);
    next();
  } catch {
    return res.status(401).json({ error: 'Invalid token' });
  }
};

The Role Middleware

const requireRole = (...roles) => (req, res, next) => {
  if (!roles.includes(req.user.role)) return res.status(403).json({ error: 'Not authorized' });
  next();
};

router.use('/admin', auth, requireRole('admin'));
router.use('/moderation', auth, requireRole('admin', 'moderator'));

Resource Ownership

For routes like /users/:id, ensure the user owns the resource or is an admin:

router.patch('/users/:id', auth, asyncHandler(async (req, res, next) => {
  if (req.user.role !== 'admin' && req.user.userId !== req.params.id) {
    return res.status(403).json({ error: 'Not authorized' });
  }
  const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
  res.json(toUserDTO(user));
}));

Permission-Based (Fine-Grained)

For fine-grained control, store permissions instead of roles:

userSchema.add({ permissions: [String] });

const requirePermission = (perm) => (req, res, next) => {
  if (!req.user.permissions?.includes(perm)) return res.status(403).json({ error: 'Not authorized' });
  next();
};

router.delete('/posts/:id', auth, requirePermission('post:delete'), deletePost);

More flexible than roles, but harder to manage at scale.

Hybrid

Common pattern: roles for coarse control, permissions for fine control. A user has a role (admin) which grants permissions (post:delete, user:ban). Store role -> permissions mapping in the DB or config.

401 vs 403

  • 401 Unauthorized: not authenticated (no token or invalid token).
  • 403 Forbidden: authenticated but not authorized (wrong role).

The Takeaway

Implement RBAC in Node.js with a role field on the user, an auth middleware that verifies the JWT and sets req.user, a requireRole factory that checks the role, and resource ownership checks for user-specific resources. For fine-grained control, use permissions. 401 for not authenticated, 403 for not authorized.

Add a role field on the user. Write an auth middleware that verifies the JWT and sets req.user. Write a requireRole factory that checks req.user.role. Apply to routes: router.use('/admin', auth, requireRole('admin')). Check resource ownership for user-specific resources.

401 Unauthorized means not authenticated (no token or invalid token). 403 Forbidden means authenticated but not authorized (wrong role or permission). Check auth first, then authorization.

Store permissions on the user (array of strings like 'post:delete', 'user:ban'). Write a requirePermission factory that checks req.user.permissions.includes(perm). More flexible than roles but harder to manage at scale.

In the handler, compare req.user.userId to the resource's owner. If they do not match and the user is not an admin, return 403. Example: if (req.user.role !== 'admin' && req.user.userId !== req.params.id) return res.status(403).

Hybrid is common. Roles for coarse control (admin, user), permissions for fine control (post:delete, user:ban). A role grants a set of permissions. Store role -> permissions mapping in the DB or config. This balances simplicity and flexibility.

Ready to master Node.js completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.