kritsana.devpassing
runartifactsdocsworkhistorydispatch

© 2026 Kritsana Prasit — built from source on a self-hosted runner

resume.pdfrssdispatch

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:

typescript
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

typescript
@Controller('cats')
@UseGuards(RolesGuard)
export class CatsController {
  @Get()
  findAll() {
    return 'This action returns all cats';
  }
}

Method-scoped Guards

typescript
@Controller('cats')
export class CatsController {
  @Get()
  @UseGuards(RolesGuard)
  findAll() {
    return 'This action returns all cats';
  }
}

Global Guards

typescript
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new RolesGuard());

Role-based Authorization

A common use case for guards is role-based authorization:

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

typescript
import { SetMetadata } from '@nestjs/common';
 
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);

Usage:

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

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

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

typescript
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

  1. Keep guards focused on authorization/authentication concerns
  2. Use dependency injection for services
  3. Combine with interceptors and pipes for complete request processing
  4. Handle errors gracefully with proper HTTP status codes
  5. 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.

more NestJS guides

  • NestJS Controllers Guide2 min read
  • NestJS Middleware Guide2 min read