Skip to main content

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 returns false or 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:

javascript
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

javascript
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):

javascript
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:

javascript
@Get('profile') @UseGuards(AuthGuard) getProfile() { ... }

2. Globally (for the whole application):

javascript
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:

javascript
canActivate(context: ExecutionContext): boolean { const request = context.switchToHttp().getRequest(); console.log(request.url); return true; }

It lets you access:

  • request and response for HTTP;
  • data and context for GraphQL;
  • client for WebSocket, and so on.

A Guard example with a JWT check

javascript
@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:

javascript
MiddlewareGuardInterceptor (before)PipeControllerInterceptor (after)

A Guard with asynchronous logic

You can return a Promise<boolean> or Observable<boolean>, Nest supports both:

javascript
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

ScenarioExample
AuthenticationChecking a JWT, API keys, sessions
AuthorizationChecking user roles (@Roles('admin'))
Conditional accessE.g. "only if the request is in an 'active' status"
Route securityRestricting public/private APIs

Summary

ConceptDescription
GuardA class that decides whether a request can be handled
InterfaceCanActivate
Main methodcanActivate(context: ExecutionContext): boolean
Resulttrue, let it through; false/an exception, block it
UseChecking permissions, tokens, roles, statuses
Levels of useMethod, controller, globally
Execution orderAfter middleware, before pipes/interceptors

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.