How to Implement Role Based Access Control in NestJS
In NestJS, implement role based access control by creating a custom
Roles decorator and a RolesGuard that checks user roles from the request. Apply the guard to routes to restrict access based on user roles securely.Syntax
To implement role based access control in NestJS, you need three main parts:
- Roles Decorator: Marks which roles can access a route.
- Roles Guard: Checks if the user has the required role.
- Applying Guard: Use the guard on controllers or routes.
typescript
import { SetMetadata, Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; // Roles decorator to set roles metadata export const Roles = (...roles: string[]) => SetMetadata('roles', roles); // RolesGuard to check roles @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler()); if (!requiredRoles) { return true; // No roles required } const request = context.switchToHttp().getRequest(); const user = request.user; return user?.roles?.some(role => requiredRoles.includes(role)); } }
Example
This example shows a simple NestJS controller with role based access. The Roles decorator marks routes for 'admin' or 'user' roles. The RolesGuard checks the user's roles from the request and allows or denies access.
typescript
import { Controller, Get, UseGuards, Req } from '@nestjs/common'; import { Roles, RolesGuard } from './roles.guard'; @Controller('dashboard') @UseGuards(RolesGuard) export class DashboardController { @Get('admin') @Roles('admin') getAdminData(@Req() req) { return { message: 'Welcome Admin', user: req.user }; } @Get('profile') @Roles('user', 'admin') getUserProfile(@Req() req) { return { message: 'User Profile', user: req.user }; } }
Output
{"message":"Welcome Admin","user":{"roles":["admin"]}}
Common Pitfalls
1. Forgetting to attach user roles to the request: The guard expects request.user.roles. Make sure authentication middleware sets this.
2. Not applying the guard globally or on routes: Without @UseGuards(RolesGuard), roles won't be checked.
3. Using wrong metadata key: The decorator and guard must use the same metadata key, e.g., 'roles'.
typescript
/* Wrong: Missing roles on user object */ // request.user = { name: 'John' } // no roles /* Right: Include roles */ // request.user = { name: 'John', roles: ['admin'] }
Quick Reference
- Roles Decorator: Use
@Roles('role1', 'role2')on routes. - Roles Guard: Implement
CanActivateto check roles. - Attach Roles: Ensure
request.user.rolesexists from auth. - Apply Guard: Use
@UseGuards(RolesGuard)on controllers or routes.
Key Takeaways
Create a custom Roles decorator to specify allowed roles on routes.
Implement a RolesGuard that checks user roles from the request object.
Always attach user roles during authentication for the guard to work.
Apply the RolesGuard using @UseGuards on controllers or specific routes.
Use consistent metadata keys between decorator and guard for role checks.