Understanding Middleware and Guards in NestJS

Laetitia Christelle Ouelle
4 min readOct 3, 2023

--

What is the difference between them ?

Hi ! In this article we will talk about the difference between middlewares and guards because I know it can be confusing sometimes.

NestJS is a popular framework for building scalable and maintainable Node.js applications. It provides various tools and mechanisms to handle different aspects of request processing and authorization/authentication. Two of these essential tools are middleware and guards.

Middleware

NestJS middleware functions are interceptors of incoming HTTP requests and outgoing responses. They allow you to process requests globally or at specific points in your application’s request/response cycle. Middleware is a tool that can perform tasks like request/response transformation, error handling, etc.

Intercepting a request can allow you to read all the information in the request itself and determine whether or not to terminate the process.

The middleware is executed before the actual route handler (controller method) is invoked. It is therefore suitable for tasks that need to be performed before the main processing of a query begins. You can apply middleware globally across your entire application, on specific routes, or even on individual route handlers.

Example of a middleware:

import { Injectable, NestMiddleware } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { Request, Response, NextFunction } from 'express';
import { getTokenStatus } from '../common/common';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
constructor(private jwt: JwtService, private config: ConfigService){}
use(req: Request, res: Response, next: NextFunction) {
console.log('Request...');
const status = getTokenStatus(req.headers.authorization, this.config.get('JWT_AT_SECRET'))
if(status.status==="valid"){
next();
}else{
res.send({message:"Invalid token"})
}
}
}

It’s an example of a NestJS middleware named LoggerMiddleware and it does the following:

  1. It logs a message to the console when a request is received.
  2. It checks the validity of a JWT token from the request’s Authorization header using a function called getTokenStatus. The JwtService and ConfigService from NestJS are injected into the middleware's constructor for this purpose.
  3. If the JWT token is valid (based on the result from getTokenStatus), it calls the next() function, allowing the request to continue processing to the next middleware or route handler.
  4. If the JWT token is invalid, it sends a JSON response with a “Invalid token” message.

This middleware can be applied to specific routes or globally within your NestJS application to perform token validation and logging for incoming requests.

Keep in mind that this example is simplified, and a real-world application would typically have more comprehensive error handling and potentially store more information about the error or unauthorized access.

Guard

NestJS guards are primarily concerned with access control and route-level authentication. They determine whether a request should be allowed to access a route handler based on certain conditions. Guards are often used to protect routes from unauthorized access or to make decisions based on request metadata, such as user roles or JWT tokens.

Unlike middleware, protections are typically applied directly to routes or route handlers, acting as gatekeepers, deciding whether a request should be forwarded to the route manager or whether it should be blocked and potentially redirected or denied. Guards are essential for strengthening security and ensuring that only authorized users or requests are allowed to access certain parts of your application.

You can implement custom guards by creating classes that implement the CanActivate or CanActivateContext interfaces.

Example of Guard

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';

@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
// Check if user is authenticated (e.g., using JWT)
return request.isAuthenticated();
}
}

It checks whether the user is authenticated. The specific implementation of isAuthenticated() will depend on how you've set up authentication in your NestJS application.

You can use this AuthGuard by applying it to your routes or route handlers using the @UseGuards() decorator in your controller:

import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from './auth.guard';

@Controller('post')
export class PostController {
@Get('all')
@UseGuards(AuthGuard)
getAllPosts() {
// Protected by the AuthGuard
// Only authenticated users can access it.
}
}

It basically means that only an authenticated user can have access to the post route.

So event if you can implement both middleware and Guards on specific routes, keep in mind that :

Middleware

  • Middleware functions intercept both incoming HTTP requests and outgoing responses.
  • They can read and manipulate the request and response objects directly.
  • Middleware is executed before the route handler (controller method) is invoked, allowing you to perform actions before the main request processing begins.

Guards

  • Guards are primarily focused on access control and route-level authentication.
  • They are applied to routes or route handlers to make decisions about whether a request should be allowed to access the associated route.
  • Guards do not directly intercept the HTTP request or response objects like middleware.
  • Guards have access to the route’s execution context and can make decisions based on request metadata (e.g., user roles, JWT tokens) or custom logic.
  • If a guard returns false or throws an exception, it can prevent the request from reaching the route handler.

Which is executed first?

In NestJS, middleware is executed before guards.

When a request is made to a route, the order of execution is like :

Middleware ====> Guards ====> Route Handler

Well! I did a lot of repetition because you can often confuse the two, or not fully understand why and when to use each.

I hope this article helped you understand better.

--

--

Laetitia Christelle Ouelle
Laetitia Christelle Ouelle

Written by Laetitia Christelle Ouelle

Hi! I'm a FullStack Software Engineer (React, NextJs, Flutter, Python, Javascript) ! Also passionate about AR, BlockChain and Google products.

Responses (1)