Mastering Guards in NestJS: Handling Authorisation and Request Control


In a real-world application, controlling access to routes and resources is critical. NestJS Guards provide a clean, declarative way to implement authorization, authentication, and request validation logic before a request reaches your route handlers.
In this guide, we’ll explore what Guards are, how they work, and how you can build both simple and dynamic Guards to secure your NestJS applications.
2. Creating a Simple Guard
Let’s create a simple authentication guard.
Step 1: Auth Guard (auth.guard.ts
)
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
if (!request.headers.authorization) {
throw new UnauthorizedException('Authorization header missing');
}
return true;
}
}
ExecutionContext
gives access to the request, response, and other context details.You can throw exceptions like
UnauthorizedException
to block the request.
3. Applying Guards
You can apply Guards at three levels:
3.1 Method Level
@UseGuards(AuthGuard)
@Get('profile')
getProfile() {
return { message: 'This is a protected route' };
}
3.2 Controller Level
@UseGuards(AuthGuard)
@Controller('users')
export class UserController { ... }
3.3 Global Level (main.ts)
app.useGlobalGuards(new AuthGuard());
Applying globally means all routes will pass through the Guard.
4. Building a Role-Based Authorization Guard
Let’s build a more dynamic guard that checks for user roles.
Step 1: Define Roles Metadata
Create a custom decorator roles.decorator.ts
:
import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
This attaches metadata to route handlers.
Step 2: Create RolesGuard
import { CanActivate, ExecutionContext, Injectable, ForbiddenException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
if (!roles) return true;
const request = context.switchToHttp().getRequest();
const user = request.user;
if (!user || !roles.includes(user.role)) {
throw new ForbiddenException('You do not have access to this resource');
}
return true;
}
}
Reflector
is a helper to read metadata set by decorators.This Guard checks if the user has one of the required roles.
Step 3: Usage Example
@Roles('admin')
@UseGuards(RolesGuard)
@Delete('remove/:id')
removeUser(@Param('id') id: string) {
return this.userService.remove(id);
}
5. Accessing Request Details Inside Guards
Guards are very flexible. You can:
Access headers, params, body
Read cookies
Check JWT tokens
Integrate third-party authentication providers (e.g., OAuth)
const request = context.switchToHttp().getRequest();
const token = request.cookies['auth-token'];
6. Best Practices for Guards
Keep Guards small and focused — one Guard per concern (e.g., authentication vs. authorization).
Combine Guards where necessary using
@UseGuards(Guard1, Guard2)
.Prefer using decorators (
@Roles
,@Public
) to control routes declaratively.Throw specific exceptions (
UnauthorizedException
,ForbiddenException
) for clarity.
Conclusion
Guards are essential for building secure, resilient NestJS applications. By controlling access before requests hit your business logic, you can cleanly enforce authentication, authorization, and custom rules at the framework level.
Whether you're protecting admin routes, implementing role-based access control, or integrating with external auth providers, Guards give you the flexibility you need to maintain a clean and scalable
Subscribe to my newsletter
Read articles from Muhire Josué directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Muhire Josué
Muhire Josué
I am a backend developer, interested in writing about backend engineering, DevOps and tooling.