Role-Based Authorization in NestJS
Authorization is a critical aspect of application security. It ensures that users can access only the resources they’re permitted to. In NestJS, a progressive Node.js framework, implementing role-based authorization is straightforward thanks to its modular design and support for decorators.
What is Role-Based Authorization?
Role-based authorization assigns permissions to users based on their roles. Common roles include “admin,” “user,” and “guest.” Each role has a predefined set of actions it can perform. For example:
- Admin: Can manage all resources.
- User: Can read and update their own data.
- Guest: Can only view public resources.
By implementing role-based authorization, you can easily control access within your application.
Setting Up Role-Based Authorization in NestJS
Here’s how you can implement role-based authorization in NestJS:
1. Install Dependencies
First, ensure you have a NestJS project set up. If not, you can create one using the CLI:
npm i -g @nestjs/cli
nest new my-app
Next, install @nestjs/passport
and passport
for authentication support:
npm install @nestjs/passport passport passport-jwt
npm install --save-dev @types/passport-jwt
2. Define Roles
Create a roles.enum.ts
file to define roles as an enum:
export enum Role {
Admin = 'admin',
User = 'user',
Guest = 'guest',
}
3. Create a Roles Guard
Guards in NestJS intercept requests before they reach route handlers. Create a custom guard to enforce role-based access control.
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Role } from './roles.enum';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<Role[]>('roles', context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
return roles.some((role) => user?.roles?.includes(role));
}
}
4. Create a Roles Decorator
To simplify the process of adding roles to route handlers, create a custom decorator:
import { SetMetadata } from '@nestjs/common';
import { Role } from './roles.enum';
export const Roles = (...roles: Role[]) => SetMetadata('roles', roles);
5. Apply the Roles Guard Globally or Locally
To make the RolesGuard
active, you can apply it globally or locally. For global application, add it to your AppModule
:
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { RolesGuard } from './roles.guard';
@Module({
providers: [
{
provide: APP_GUARD,
useClass: RolesGuard,
},
],
})
export class AppModule {}
For local application, use it in specific controllers or methods:
import { Controller, Get, UseGuards } from '@nestjs/common';
import { Roles } from './roles.decorator';
import { RolesGuard } from './roles.guard';
import { Role } from './roles.enum';
@Controller('resources')
@UseGuards(RolesGuard)
export class ResourcesController {
@Get()
@Roles(Role.Admin, Role.User)
findAll() {
return 'This endpoint is accessible to Admins and Users.';
}
}
6. Authenticate Users
To identify a user’s roles, ensure your authentication process adds the roles to the user
object in the request. This often involves decoding a JWT or using a session store.
Example Authentication Middleware
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class AuthMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const token = req.headers['authorization'];
if (token) {
const decoded = this.decodeToken(token); // Implement JWT decoding
req.user = decoded;
}
next();
}
private decodeToken(token: string): any {
// Logic to decode JWT and retrieve user data
return { roles: ['user'] }; // Example decoded payload
}
}
Testing the Implementation
Start your application and test endpoints with users of different roles. Ensure each user can access only what their role permits.
Example Requests
- Admin User: Should access all routes.
- Regular User: Should access user-specific routes.
- Guest: Should be restricted to public routes.
Conclusion
Role-based authorization in NestJS is clean and efficient thanks to decorators, guards, and the framework’s modularity. By following the steps above, you can secure your application while maintaining flexibility and scalability.
For more complex scenarios, consider integrating with external libraries like Casl or implementing attribute-based access control (ABAC).
Top comments (0)