Skip to content

Mean 15 Authorization

DodaTech 6 min read

title: "Authorization — Role-Based Access Control in the MEAN Stack" description: "Implement role-based authorization in the MEAN Stack with Express middleware, user roles, permission checking, and Angular route guards." weight: 25 date: 2026-06-28 lastmod: 2026-06-28 tags: [frameworks, mean]

Authorization controls what authenticated users can do. Role-based access control (RBAC) assigns permissions based on user roles like admin, moderator, and regular user.

What You'll Learn

You will implement role-based authorization with Express middleware for API protection and Angular route guards for frontend protection.

Why It Matters

Authorization prevents users from accessing resources or performing actions they should not. It is essential for multi-user applications with different permission levels.

Real-World Use

Durga Antivirus Pro uses three roles: admin (full access), analyst (can view and update threats), and viewer (read-only). Each API endpoint checks the user's role.

flowchart TD
    A[Request] --> B[Auth Middleware]
    B --> C[Role Check Middleware]
    C --> D{User Role}
    D -->|Admin| E[Full Access]
    D -->|Moderator| F[Limited Write]
    D -->|User| G[Read Only]
    D -->|No Role| H[Deny Access]
    style B fill:#4a90d9,color:#fff
    style C fill:#4a90d9,color:#fff

User Schema with Roles

Add a role field to the user schema.

// backend/models/User.js
const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
  role: {
    type: String,
    enum: ['user', 'moderator', 'admin'],
    default: 'user'
  },
  permissions: [{
    type: String,
    enum: ['read:products', 'create:products', 'update:products', 'delete:products',
           'read:users', 'create:users', 'update:users', 'delete:users']
  }],
  active: { type: Boolean, default: true }
}, { timestamps: true });

Expected output: Users have a role field (user, moderator, admin) and an array of granular permissions.

Role-Based Middleware

Create middleware that checks user roles and permissions.

// backend/middleware/authorize.js
function 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,
        current: req.user.role
      });
    }

    next();
  };
}

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

    if (req.user.role === 'admin') {
      return next(); // Admin has all permissions
    }

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

    next();
  };
}

module.exports = { authorize, requirePermission };

Expected output: authorize('admin', 'moderator') allows only admin and moderator roles. requirePermission('delete:products') checks granular permissions.

Protecting Routes with Role Middleware

Apply authorization middleware to specific routes.

// backend/routes/adminRoutes.js
const express = require('express');
const router = express.Router();
const { authMiddleware } = require('../middleware/auth');
const { authorize, requirePermission } = require('../middleware/authorize');

// All admin routes require authentication
router.use(authMiddleware);

// Admin-only routes
router.get('/dashboard', authorize('admin'), async (req, res) => {
  const stats = await getDashboardStats();
  res.json(stats);
});

router.get('/users', authorize('admin', 'moderator'), async (req, res) => {
  const users = await User.find().select('-password');
  res.json(users);
});

// Permission-based routes
router.delete('/products/:id',
  requirePermission('delete:products'),
  async (req, res) => {
    await Product.findByIdAndDelete(req.params.id);
    res.status(204).send();
  }
);

router.post('/products',
  requirePermission('create:products'),
  async (req, res) => {
    const product = await Product.create(req.body);
    res.status(201).json(product);
  }
);

Expected output: Admin dashboard is admin-only. User list is accessible to admin and moderator. Delete requires specific permission.

Angular Route Guards

Protect frontend routes based on user roles.

// src/app/guards/role.guard.ts
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';

export function roleGuard(...allowedRoles: string[]): CanActivateFn {
  return () => {
    const authService = inject(AuthService);
    const router = inject(Router);

    const user = authService.getCurrentUser();
    if (!user) {
      return router.parseUrl('/login');
    }

    if (!allowedRoles.includes(user.role)) {
      return router.parseUrl('/unauthorized');
    }

    return true;
  };
}

// Usage in routes
{
  path: 'admin',
  loadComponent: () => import('./components/admin/admin.component')
    .then(m => m.AdminComponent),
  canActivate: [roleGuard('admin')],
  title: 'Admin Panel'
},
{
  path: 'users',
  loadComponent: () => import('./components/user-list/user-list.component')
    .then(m => m.UserListComponent),
  canActivate: [roleGuard('admin', 'moderator')],
  title: 'Users'
}

Expected output: Admin route is only accessible to admin users. Users route is accessible to admin and moderator. Unauthorized users are redirected.

Conditional UI Rendering

Show or hide UI elements based on user roles and permissions.

// In component
export class ProductListComponent {
  user$ = this.authService.user$;

  constructor(private authService: AuthService) {}

  canDelete(): boolean {
    const user = this.authService.getCurrentUser();
    return user?.role === 'admin' || user?.permissions?.includes('delete:products');
  }
}
<!-- Template -->
<div *ngIf="user$ | async as user">
  <button *ngIf="user.role === 'admin' || user.permissions.includes('delete:products')"
          (click)="deleteProduct(product._id)">
    Delete
  </button>
</div>

Expected output: Delete buttons only appear for authorized users. The condition checks both role and granular permissions.

Common Mistakes

  1. Checking roles only on the frontend: Frontend checks are cosmetic. Always enforce authorization on the backend.

  2. Hardcoding user IDs for admin checks: Use role-based checks, not hardcoded IDs. The admin role should be in the database.

  3. Not handling the 403 status code in Angular: When the API returns 403, show an unauthorized page instead of a generic error.

  4. Giving all users the admin role by accident: The default role should be 'user'. Only explicitly set 'admin' for authorized users.

  5. Not excluding admin from permission checks: Admin should have all permissions. Check for admin role before checking granular permissions.

Practice Questions

  1. What is the difference between authentication and authorization?

Authentication verifies who you are. Authorization verifies what you are allowed to do.

  1. How do you protect an API route for admin users only?

Use the authorize('admin') middleware after the auth middleware. Non-admin users receive 403.

  1. How do you protect an Angular route for specific roles?

Use a role guard that checks the user's role from AuthService and redirects unauthorized users.

  1. What is the purpose of granular permissions?

They provide finer control than roles. A moderator might create products but not delete them.

  1. How do you handle unauthorized access in the UI?

Conditionally render buttons and links based on the user's role and permissions. Use *ngIf with role checks.

Challenge

Implement a complete authorization system with: three user roles (user, moderator, admin), granular permissions (CRUD per resource), backend middleware for role and permission checks, Angular route guards, and conditional UI rendering.

Frequently Asked Questions

Should I use roles or permissions?

Both. Roles group common permissions. Permissions provide granular control. Check roles first, then permissions for specific actions.

How do I assign roles to users?

Create an admin-only endpoint for updating user roles. Only existing admins can promote other users.

Can a user have multiple roles?

Mongoose supports array fields. Use role: [String] if multiple roles are needed. Adjust authorization checks accordingly.

How do I handle unauthorized API responses in Angular?

In the HTTP interceptor, handle 403 responses by showing a notification or redirecting to an unauthorized page.

What is the principle of least privilege?

Give users the minimum permissions they need to do their job. Start with no permissions and add as needed.

Mini Project

Build an admin panel with three user levels: admin (full access, can manage users), editor (can create and edit posts but not delete), and viewer (can only view). Implement backend authorization and frontend UI hiding.

What's Next

Learn File Upload handling in the MEAN stack.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro