Skip to content

11 Authorization Middleware

DodaTech 4 min read

title: Authorization Middleware in Node.js REST APIs weight: 21 date: 2026-06-28 lastmod: 2026-06-28 description: Learn role-based and permission-based authorization middleware in Node.js REST APIs for controlling access to endpoints based on user roles and resource ownership. tags: [api-development, nodejs]


Authorization middleware in Node.js REST APIs controls access to endpoints by checking user roles, permissions, and resource ownership after authentication, ensuring users can only perform allowed actions.

```mermaid
flowchart TD
  A[Authenticated Request] --> B{Auth Middleware}
  B -->|Has role admin| C[Allow Access]
  B -->|Is resource owner| C
  B -->|No permission| D[403 Forbidden]
  B -->|Not authenticated| E[401 Unauthorized]
  style A fill:#e1f5fe
  style B fill:#fff9c4
  style C fill:#c8e6c9
  style D fill:#ffcdd2

Authorization checks happen after authentication. Two common patterns: role-based access control (RBAC) checks if the user has the required role, and resource-based access control checks if the user owns the resource being accessed. Middleware functions can be chained.

Think of authorization like different employee badges in a building. Authentication proves you are an employee (Anyone with a badge). Authorization determines which floors you can access (RBAC: admin gets all floors, regular employee gets only theirs).

Example: Role-Based Authorization

const authorize = (...allowedRoles) => {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(401).json({ error: 'Authentication required' });
    }

    if (!allowedRoles.includes(req.user.role)) {
      return res.status(403).json({
        error: 'Insufficient permissions',
        required: allowedRoles,
        yourRole: req.user.role
      });
    }

    next();
  };
};

// Usage
app.delete('/api/users/:id',
  authenticate,
  authorize('admin'),
  userController.deleteUser
);

app.get('/api/users',
  authenticate,
  authorize('admin', 'editor'),
  userController.listUsers
);

Example: Resource Ownership Authorization

const authorizeOwner = (resourceGetter) => {
  return async (req, res, next) => {
    try {
      const resource = await resourceGetter(req);
      
      if (!resource) {
        return res.status(404).json({ error: 'Resource not found' });
      }

      // Admin can access any resource
      if (req.user.role === 'admin') {
        req.resource = resource;
        return next();
      }

      // Check ownership
      if (resource.userId !== req.user.userId) {
        return res.status(403).json({
          error: 'You do not own this resource'
        });
      }

      req.resource = resource;
      next();
    } catch (error) {
      next(error);
    }
  };
};

// Usage
app.patch('/api/orders/:id',
  authenticate,
  authorizeOwner((req) => findOrder(req.params.id)),
  orderController.updateOrder
);

Example: Permission-Based Authorization

// Permission definitions
const permissions = {
  'user:read': ['admin', 'editor', 'viewer'],
  'user:write': ['admin', 'editor'],
  'user:delete': ['admin'],
  'order:read': ['admin', 'editor', 'viewer'],
  'order:write': ['admin', 'editor'],
  'user:read:own': ['*']  // All authenticated users
};

const hasPermission = (permission) => {
  return (req, res, next) => {
    const allowedRoles = permissions[permission];
    
    if (!allowedRoles) {
      return res.status(500).json({ error: 'Undefined permission' });
    }

    // * means all authenticated users
    if (allowedRoles.includes('*')) {
      return next();
    }

    if (!allowedRoles.includes(req.user.role)) {
      return res.status(403).json({
        error: 'Missing permission',
        required: permission
      });
    }

    next();
  };
};

// Usage
router.post('/users', hasPermission('user:write'), userController.createUser);
router.delete('/users/:id', hasPermission('user:delete'), userController.deleteUser);

Common Mistakes

  1. Confusing authentication with authorization — Authentication verifies identity. Authorization verifies permissions. Both are needed but are separate concerns.
  2. Checking roles without resource ownership — A user with role editor should not edit other users' orders. Check both role and ownership.
  3. Hard-coding user IDs from tokens — Always verify the user from the token matches the resource owner. Never trust user IDs from request bodies.
  4. Not handling the 403 vs 401 distinction — 401 means unauthenticated (not logged in). 403 means authenticated but not permitted. Using the wrong code confuses clients.
  5. Insufficient test coverage for authorization — Test every authorization rule with users of each role, unauthenticated users, and resource owners vs non-owners.

Practice Questions

  1. What is the difference between 401 and 403 status codes?
  2. How do you implement resource-based authorization?
  3. What is RBAC and how does it work?
  4. Why should authorization be middleware rather than inline checks?
  5. Challenge: Build an authorization system that combines role-based and resource-based checks. Include admin override, ownership verification, and permission-based access. Test with a blog API where authors can edit their own posts and admins can edit any post.

FAQ

Should authorization middleware run before or after auth middleware?

After. Authorization requires the user identity from authentication. Chain them: app.use('/admin', authenticate, authorize('admin')).

What is the difference between RBAC and ABAC?

RBAC uses roles (admin, editor). ABAC uses attributes (department=engineering, clearance=level3). ABAC is more flexible but complex to implement.

How do I handle authorization for nested resources?

Check ownership at each level: can this user access user 42's order 5? Verify user 42 matches the authenticated user (unless admin).

Should I return 403 or 404 for unauthorized access?

Return 403 to indicate the resource exists but access is denied. Returning 404 (pretending it does not exist) is a security pattern for hiding resource existence.

How do I test authorization rules?

Create test users for each role. Write tests that verify: allowed users can access, disallowed users get 403, unauthenticated users get 401, and resource owners vs non-owners are handled correctly.

Mini Project

Build a complete authorization system for a blog API. Implement role-based access (admin, editor, author, viewer), resource ownership (authors edit own posts), and permission-based checks. Apply to endpoints: create/edit/delete posts, moderate comments, manage users.

What's Next

Now learn about database integration with Mongoose and Prisma in Building REST APIs with Node.js.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro