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

Walkthrough

Space play step click any line
Three takeaways
  1. 1A guard is any class implementing canActivate that returns true to allow the request or throws to reject it.
  2. 2Chaining small single-purpose guards keeps authentication, role checks, and resource access independent and composable.
  3. 3Guards can attach data to the request object so later guards and handlers build on earlier work.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How guards chain auth in NestJS — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code