Auth Guards

The Most Common Use of Guards

Auth Guards

Auth guards check a token or session, attach the authenticated user to the request, and either let it through or reject it.

4 min read Level 2/5 #nestjs#guards#auth
What you'll learn
  • Write a JWT-validating guard from scratch
  • Use AuthGuard from @nestjs/passport for built-in strategies
  • Stack guards (authentication, then authorization)

Auth is the canonical guard use case. A guard reads a token from the request, verifies it, looks up the user, and either continues or rejects.

A Hand-Rolled JWT Guard

If you only need JWT validation, you don’t have to pull in Passport at all.

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

@Injectable()
export class JwtAuthGuard implements CanActivate {
  constructor(private readonly jwt: JwtService) {}

  async canActivate(ctx: ExecutionContext): Promise<boolean> {
    const req = ctx.switchToHttp().getRequest();
    const auth = req.headers.authorization ?? '';
    const [scheme, token] = auth.split(' ');
    if (scheme !== 'Bearer' || !token) {
      throw new UnauthorizedException('missing bearer token');
    }
    try {
      req.user = await this.jwt.verifyAsync(token);
      return true;
    } catch {
      throw new UnauthorizedException('invalid token');
    }
  }
}

Apply it like any other guard:

@Controller('me')
@UseGuards(JwtAuthGuard)
export class MeController {
  @Get()
  me(@Req() req: Request) {
    return req.user; // populated by the guard
  }
}

Using Passport Strategies

When you want OAuth, sessions, or other strategies, @nestjs/passport wraps Passport’s library and exposes guards keyed by strategy name.

import { AuthGuard } from '@nestjs/passport';

// 'jwt' is the strategy name registered in your auth module
export class JwtAuthGuard extends AuthGuard('jwt') {}

@Controller('protected')
@UseGuards(JwtAuthGuard)
export class ProtectedController {
  @Get() data() { return 'top secret'; }
}

The matching JwtStrategy (a separate class that extends PassportStrategy) does the actual verification — the guard just plugs Passport into Nest’s pipeline.

Stacking Authentication and Authorization

You almost always want two layers: authn (“who are you?”) and authz (“are you allowed to do this?”). @UseGuards accepts multiple — they run in order, short-circuiting on the first failure.

@Delete(':id')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
remove(@Param('id') id: string) {
  return this.users.remove(id);
}

JwtAuthGuard runs first and attaches req.user. RolesGuard then reads the @Roles metadata and req.user.roles to decide. (You’ll build that roles guard in the metadata lesson.)

Optional Auth

Sometimes you want a route that works for both anonymous and authenticated users — return personalized content if logged in, public content otherwise. Solve it with a “passive” guard that always returns true but still attempts to attach a user:

async canActivate(ctx: ExecutionContext): Promise<boolean> {
  try { await this.attachUserIfPresent(ctx); } catch { /* ignore */ }
  return true;
}

Auth guards are usually the first thing you wire into a serious Nest app. Get them right and the rest of your security model has a stable foundation.

Interceptors — Wrap the Pipeline →