typescript
72 lines · 8 steps
How guards chain auth in NestJS
Three NestJS guards run in sequence to authenticate, authorize by role, and check workspace membership on each request.
Explained by
highlit
1import {
2 CanActivate,
3 ExecutionContext,
4 Injectable,
5 ForbiddenException,
6} from '@nestjs/common';
7import { Reflector } from '@nestjs/core';
8import { Request } from 'express';
9
10@Injectable()
11export class JwtAuthGuard implements CanActivate {
12 canActivate(context: ExecutionContext): boolean {
13 const req = context.switchToHttp().getRequest<Request>();
14 const token = req.headers.authorization?.replace('Bearer ', '');
15
16 if (!token) {
17 throw new ForbiddenException('Missing bearer token');
18 }
19
20 req['user'] = this.decode(token);
21 return true;
22 }
23
24 private decode(token: string) {
25 const [, payload] = token.split('.');
26 return JSON.parse(Buffer.from(payload, 'base64url').toString());
27 }
28}
29
30@Injectable()
31export class RolesGuard implements CanActivate {
32 constructor(private readonly reflector: Reflector) {}
33
34 canActivate(context: ExecutionContext): boolean {
35 const required = this.reflector.getAllAndOverride<string[]>('roles', [
36 context.getHandler(),
37 context.getClass(),
38 ]);
39
40 if (!required?.length) {
41 return true;
42 }
43
44 const { user } = context.switchToHttp().getRequest<Request>();
45 const granted = required.some((role) => user?.roles?.includes(role));
46
47 if (!granted) {
48 throw new ForbiddenException('Insufficient role');
49 }
50
51 return true;
52 }
53}
54
55@Injectable()
56export class WorkspaceGuard implements CanActivate {
57 constructor(private readonly memberships: MembershipService) {}
58
59 async canActivate(context: ExecutionContext): Promise<boolean> {
60 const req = context.switchToHttp().getRequest<Request>();
61 const isMember = await this.memberships.exists(
62 req['user'].sub,
63 req.params.workspaceId,
64 );
65
66 if (!isMember) {
67 throw new ForbiddenException('Not a workspace member');
68 }
69
70 return true;
71 }
72}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A guard is any class implementing canActivate that returns true to allow the request or throws to reject it.
- 2Chaining small single-purpose guards keeps authentication, role checks, and resource access independent and composable.
- 3Guards can attach data to the request object so later guards and handlers build on earlier work.
Related explainers
go
package security import ( "crypto/hmac"
Signing and verifying payloads with HMAC in Go
hmac
cryptography
authentication
Intermediate
5 steps
typescript
import { Injectable, NotFoundException, ConflictException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, DeepPartial } from 'typeorm'; import { User } from './entities/user.entity';
Building a CRUD service in NestJS
crud
dependency-injection
repository-pattern
Intermediate
7 steps
typescript
type AsyncMethod = (...args: any[]) => Promise<any>; function LogExecutionTime(thresholdMs = 0) { return function <T extends AsyncMethod>(
A method decorator that times async calls
decorators
higher-order-functions
async
Advanced
9 steps
typescript
import { Controller, Get, Param, Query, Redirect, NotFoundException } from '@nestjs/common'; import { LinksService } from './links.service'; @Controller('links')
Handling HTTP redirects in NestJS
redirects
routing
decorators
Intermediate
7 steps
python
from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from jose import JWTError, jwt from sqlalchemy.orm import Session
Chaining auth dependencies in FastAPI
dependency-injection
jwt-authentication
authorization
Intermediate
8 steps
typescript
import { useState, useCallback } from 'react'; type Todo = { id: string;
Optimistic UI updates in a React hook
optimistic-updates
custom-hooks
error-handling
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-guards-chain-auth-in-nestjs-explained-typescript-5e24/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.