Skip to content

Node.js Authorization — Complete Guide to Role-Based Access Control

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Node.js Authorization. We cover key concepts, practical examples, and best practices to help you master this topic.

Node.js authorization controls what authenticated users can do, implementing role-based access control (RBAC), permissions, and resource-level access rules.

What You'll Learn

By the end of this tutorial, you'll implement RBAC with roles and permissions, create authorization middleware, protect API routes, and handle resource-level ownership checks.

Why Authorization Matters

Authentication tells you who the user is. Authorization tells you what they can do. Without proper authorization, users can access other users' data or perform admin actions.

Real-World Use

A project management app has three roles: Admin (all access), Manager (create/edit projects), Member (view and comment). Authorization middleware ensures each user can only perform allowed actions.

Authorization Learning Path

flowchart LR
  A[Authentication] --> B[Authorization]
  B --> C[File Upload]
  C --> D[Caching]
  D --> E[Docker]
  A --> F{You Are Here}
  style F fill:#f90,color:#fff

Role-Based Access Control

const ROLES = { ADMIN: "admin", MANAGER: "manager", USER: "user" };
const PERMISSIONS = {
  [ROLES.ADMIN]: ["read:users", "create:users", "delete:users", "read:reports"],
  [ROLES.MANAGER]: ["read:users", "create:users", "read:reports"],
  [ROLES.USER]: ["read:own"]
};
function hasPermission(user, permission) {
  const permissions = PERMISSIONS[user.role];
  return permissions && permissions.includes(permission);
}

Authorization Middleware

function authorize(...allowedRoles) {
  return (req, res, next) => {
    if (!req.user) return res.status(401).json({ error: "Not authenticated" });
    if (!allowedRoles.includes(req.user.role)) {
      return res.status(403).json({ error: "Insufficient permissions" });
    }
    next();
  };
}
// Usage
app.get("/api/admin/users", authenticate, authorize("admin"), async (req, res) => {
  const users = await db.users.findAll();
  res.json(users);
});

Resource Ownership

async function checkOwnership(model, paramName = "id") {
  return async (req, res, next) => {
    const resource = await db[model].findById(req.params[paramName]);
    if (!resource) return res.status(404).json({ error: "Not found" });
    if (resource.userId !== req.user.id && req.user.role !== "admin") {
      return res.status(403).json({ error: "Access denied" });
    }
    req.resource = resource;
    next();
  };
}
app.get("/api/posts/:id", authenticate, checkOwnership("posts"), (req, res) => {
  res.json(req.resource);
});

Permission-Based Middleware

function requirePermission(permission) {
  return (req, res, next) => {
    if (!req.user) return res.status(401).json({ error: "Not authenticated" });
    if (!hasPermission(req.user, permission)) {
      return res.status(403).json({ error: "Permission denied" });
    }
    next();
  };
}
app.delete("/api/users/:id", authenticate, requirePermission("delete:users"), handler);

ACL Implementation

const acl = new Map();
function grant(userId, resource, action) {
  const key = `${userId}:${resource}`;
  if (!acl.has(key)) acl.set(key, []);
  acl.get(key).push(action);
}
function checkAccess(userId, resource, action) {
  const key = `${userId}:${resource}`;
  const actions = acl.get(key);
  return actions && actions.includes(action);
}

Common Mistakes

1. Only Checking Authentication, Not Authorization

Authenticated doesn't mean authorized. Always check permissions after authentication.

2. Hardcoding Role Checks with Magic Strings

Use constants for role names. Hardcoded strings cause bugs when role names change.

3. Forgetting Resource Ownership

A user with role "user" should only access their own resources. Check ownership in addition to roles.

4. Returning 401 vs 403 Incorrectly

401 means unauthenticated (not logged in). 403 means authenticated but not authorized (wrong role). Use the correct status code.

5. Not Testing Authorization Edge Cases

Test that unauthorized users get 403 for every protected route. Test that authorized users can access their routes.

Practice Questions

1. What is the difference between authentication and authorization?

Authentication verifies identity. Authorization determines what actions the authenticated user can perform.

2. What is RBAC?

Role-Based Access Control assigns permissions to roles and roles to users. A user's role determines what they can do.

3. How do you implement resource-level authorization?

Check that the resource's owner ID matches the authenticated user's ID (or the user has admin role).

4. What HTTP status code indicates insufficient permissions?

403 Forbidden. 401 is for missing or invalid authentication.

5. Challenge: Implement a permission system where admins can delete any post, but users can only delete their own posts.

app.delete("/api/posts/:id", authenticate, async (req, res) => {
  const post = await db.posts.findById(req.params.id);
  if (!post) return res.status(404).json({ error: "Not found" });
  if (post.userId !== req.user.id && req.user.role !== "admin") {
    return res.status(403).json({ error: "Not authorized" });
  }
  await db.posts.delete(req.params.id);
  res.status(204).send();
});

FAQ

What is the difference between RBAC and ABAC?

RBAC uses roles (admin, user). ABAC uses attributes (user department, time of day, resource sensitivity). ABAC is more flexible but complex.

Should authorization be in middleware or route handlers?

Middleware for role/permission checks. Route handlers for resource ownership. This keeps code DRY and testable.

How do I test authorization logic?

Write unit tests for each permission check. Use integration tests with different user roles to verify access control.

Can I use JWT claims for authorization?

Yes. Include role and permissions in JWT payload. Verify on each request without database lookup.

What is the principle of least privilege?

Users should have minimum permissions needed to do their job. Grant specific permissions, not broad access.

Mini Project: RBAC System

Build a complete RBAC system with roles, permissions, and middleware.

const ROLES = { ADMIN: "admin", EDITOR: "editor", VIEWER: "viewer" };
const PERMISSIONS = {
  [ROLES.ADMIN]: ["create", "read", "update", "delete"],
  [ROLES.EDITOR]: ["create", "read", "update"],
  [ROLES.VIEWER]: ["read"]
};
function authorize(action) {
  return (req, res, next) => {
    const userPerms = PERMISSIONS[req.user?.role];
    if (!userPerms?.includes(action)) {
      return res.status(403).json({ error: "Forbidden" });
    }
    next();
  };
}
app.post("/api/articles", authenticate, authorize("create"), handler);
app.get("/api/articles", authenticate, authorize("read"), handler);
app.put("/api/articles/:id", authenticate, authorize("update"), handler);
app.delete("/api/articles/:id", authenticate, authorize("delete"), handler);

What's Next

Node.js File Upload Node.js Caching Redis Node.js Docker

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro