Guards
Guards in NestJS v10 are a crucial feature for controlling access to controller methods. They allow you to check specific conditions before a controller method is executed, determining whether the request should proceed.
Introduction to Guards
Guards are a mechanism in NestJS used to perform checks before a controller method is invoked. They are commonly used for authentication, authorization, role-based access control, and similar scenarios.
Creating Guards
To create a guard, you need to implement the CanActivate interface.
// src/guards/auth.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
return request.isAuthenticated(); // Assumes an isAuthenticated method to check if the user is logged in
}
}Using Guards
Guards can be applied at the method level or globally across the application.
// src/controllers/users.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from './guards/auth.guard';
@Controller('users')
export class UsersController {
@Get()
@UseGuards(AuthGuard)
findAll() {
// Only requests passing the AuthGuard check will reach here
return 'Only authenticated users can see this.';
}
}Global Guards
You can set a global guard to avoid declaring guards for each controller or method.
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AuthGuard } from './guards/auth.guard';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new AuthGuard());
await app.listen(3000);
}
bootstrap();Local Guards
Local guards can be applied to specific controllers or methods.
// src/controllers/users.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from './guards/auth.guard';
@Controller('users')
export class UsersController {
@Get()
@UseGuards(AuthGuard)
findAll() {
// Only requests passing the AuthGuard check will reach here
return 'Only authenticated users can see this.';
}
}Multiple Guards
You can apply multiple guards to a single controller method.
// src/controllers/admin.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from './guards/auth.guard';
import { RoleGuard } from './guards/role.guard';
@Controller('admin')
export class AdminController {
@Get()
@UseGuards(AuthGuard, RoleGuard)
index() {
return 'Admin page';
}
}Dependency Injection in Guards
Guards can leverage dependency injection to access other services as needed.
// src/guards/role.guard.ts
import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ROLES_KEY } from './roles.decorator';
@Injectable()
export class RoleGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
return requiredRoles.some(role => user.roles.includes(role));
}
}Roles Decorator
To use a role-based guard, you need to create a roles decorator to specify which roles can access a particular controller method.
// src/decorators/roles.decorator.ts
import { SetMetadata } from '@nestjs/common';
export const ROLES_KEY = 'roles';
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);Using the Roles Decorator
You can now use the roles decorator on controller methods to specify which roles are allowed.
// src/controllers/admin.controller.ts
import { Controller, Get, UseGuards, Roles } from '@nestjs/common';
import { AuthGuard } from './guards/auth.guard';
import { RoleGuard } from './guards/role.guard';
import { ROLES_KEY } from './decorators/roles.decorator';
@Controller('admin')
export class AdminController {
@Get()
@UseGuards(AuthGuard, RoleGuard)
@Roles('admin')
index() {
return 'Admin page';
}
}Error Handling in Guards
When a guard blocks a request, you can customize the error response.
// src/guards/auth.guard.ts
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
if (!request.isAuthenticated()) {
throw new UnauthorizedException('You are not authenticated.');
}
return true;
}
}



