What is a Guard?
What a Guard is
A Guard is a class that decides whether a specific request is allowed to proceed. It intercepts the request before NestJS calls the controller or its method.
If a Guard returns
true→ the request proceeds. If it returnsfalseor throws → the request is blocked.
So Guards are an access-level filter. They resemble middleware, but are integrated more deeply into NestJS's lifecycle and operate at the level of routes, controllers, and modules.
The Guard interface
To create a Guard, you implement the CanActivate interface
and define a canActivate() method:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
// the check's logic
return true; // or false
}
}The canActivate() method
- is called before the route handler runs;
- returns:
true→ access allowed,false→ access denied,- or throws (
throw new UnauthorizedException()).
A simple Guard example
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const authHeader = request.headers['authorization'];
if (!authHeader || authHeader !== 'Bearer secret123') {
throw new UnauthorizedException('Access denied');
}
return true; // access allowed
}
}This Guard checks for an Authorization header.
If the token is wrong, it throws an error.
Attaching a Guard
1. Locally (at the method or controller level):
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from './auth.guard';
@Controller('users')
@UseGuards(AuthGuard) // applies to every method
export class UsersController {
@Get()
findAll() {
return ['John', 'Alex'];
}
}Or on a single method:
@Get('profile')
@UseGuards(AuthGuard)
getProfile() { ... }2. Globally (for the whole application):
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AuthGuard } from './auth.guard';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new AuthGuard()); // a global guard
await app.listen(3000);
}
bootstrap();What ExecutionContext does
ExecutionContext is an object that gives access to the current execution context (HTTP, WebSocket, RPC).
An HTTP example:
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
console.log(request.url);
return true;
}It lets you access:
requestandresponsefor HTTP;dataandcontextfor GraphQL;clientfor WebSocket, and so on.
A Guard example with a JWT check
@Injectable()
export class JwtAuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const req = context.switchToHttp().getRequest();
const auth = req.headers['authorization'];
if (!auth?.startsWith('Bearer ')) {
throw new UnauthorizedException('Missing token');
}
const token = auth.split(' ')[1];
// a JWT check would go here
if (token !== 'valid-token') {
throw new UnauthorizedException('Invalid token');
}
return true;
}
}When Guards get called
Guards run before pipes and interceptors.
The order:
Middleware → Guard → Interceptor (before) → Pipe → Controller → Interceptor (after)A Guard with asynchronous logic
You can return a Promise<boolean> or Observable<boolean>, Nest supports both:
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const isValid = await this.authService.validateToken(request.headers.authorization);
return isValid;
}When Guards are worth using
| Scenario | Example |
|---|---|
| Authentication | Checking a JWT, API keys, sessions |
| Authorization | Checking user roles (@Roles('admin')) |
| Conditional access | E.g. "only if the request is in an 'active' status" |
| Route security | Restricting public/private APIs |
Summary
| Concept | Description |
|---|---|
| Guard | A class that decides whether a request can be handled |
| Interface | CanActivate |
| Main method | canActivate(context: ExecutionContext): boolean |
| Result | true, let it through; false/an exception, block it |
| Use | Checking permissions, tokens, roles, statuses |
| Levels of use | Method, controller, globally |
| Execution order | After middleware, before pipes/interceptors |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.