docs / NestJS
NestJS Guards and Authentication
Implement authentication and authorization in NestJS using guards to protect your routes and resources.
3 min read
NestJS Guards: Protecting Your Routes
Guards are execution contexts in NestJS that determine whether a request should be handled by the route handler or not. They're perfect for implementing authentication, authorization, and other access control mechanisms.
Understanding Guards
Guards have a single responsibility: to determine if a request should be handled by the route handler. They make this decision based on certain conditions (like permissions, roles, ACLs, etc.) present at run-time.
Creating a Basic Guard
Here's how to create a simple authentication guard:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return validateRequest(request);
}
}
function validateRequest(request: any): boolean {
// Your authentication logic here
// For example, check if the request has a valid JWT token
return true; // or false
}Binding Guards
Guards can be controller-scoped, method-scoped, or global.
Controller-scoped Guards
@Controller('cats')
@UseGuards(RolesGuard)
export class CatsController {
@Get()
findAll() {
return 'This action returns all cats';
}
}Method-scoped Guards
@Controller('cats')
export class CatsController {
@Get()
@UseGuards(RolesGuard)
findAll() {
return 'This action returns all cats';
}
}Global Guards
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new RolesGuard());Role-based Authorization
A common use case for guards is role-based authorization:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@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;
}
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some(role => user.roles?.includes(role));
}
}And then use it with a custom decorator:
import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);Usage:
@Controller('cats')
export class CatsController {
@Get()
@Roles('admin')
@UseGuards(RolesGuard)
findAll() {
return 'This action returns all cats';
}
}JWT Authentication Guard
Here's a more practical example using JWT authentication:
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
handleRequest(err, user, info) {
if (err || !user) {
throw err || new UnauthorizedException();
}
return user;
}
}Combining Multiple Guards
You can use multiple guards together:
@UseGuards(JwtAuthGuard, RolesGuard)
@Get('profile')
getProfile(@Request() req) {
return req.user;
}Custom Metadata for Guards
You can create custom metadata for more complex authorization scenarios:
export const RequirePermissions = (...permissions: string[]) =>
SetMetadata('permissions', permissions);
@Injectable()
export class PermissionsGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredPermissions = this.reflector.get<string[]>('permissions', context.getHandler());
if (!requiredPermissions) {
return true;
}
const { user } = context.switchToHttp().getRequest();
return requiredPermissions.every(permission => user.permissions?.includes(permission));
}
}Best Practices
- Keep guards focused on authorization/authentication concerns
- Use dependency injection for services
- Combine with interceptors and pipes for complete request processing
- Handle errors gracefully with proper HTTP status codes
- Write unit tests for your guards
By implementing guards effectively, you can ensure that your NestJS application's routes are properly protected and only accessible to authorized users.