Passport.js in Nest

Strategies for Every Auth Provider You Need

Passport.js in Nest

Nest wraps Passport so each authentication strategy becomes a Nest provider you can compose and test like any other.

4 min read Level 2/5 #nestjs#passport#auth
What you'll learn
  • Install @nestjs/passport and a strategy package
  • Implement a PassportStrategy subclass
  • Use AuthGuard('strategy') to protect routes

Passport is the Node ecosystem’s auth Swiss Army knife: a small core plus 500+ “strategies” for everything from username/password to SAML. Nest’s @nestjs/passport package lets you use any of them as a Nest provider.

Install

npm i @nestjs/passport passport passport-local
npm i -D @types/passport-local

The pattern is the same for every strategy: install the strategy npm package, subclass PassportStrategy, register it as a provider.

A Local Strategy

“Local” is Passport-speak for username/password. Subclass PassportStrategy(Strategy) and implement validate.

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-local';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly auth: AuthService) {
    super({ usernameField: 'email' });
  }

  async validate(email: string, password: string) {
    const user = await this.auth.verify(email, password);
    if (!user) throw new UnauthorizedException();
    return user;
  }
}

Whatever validate returns is attached to req.user for downstream handlers. Throwing UnauthorizedException short-circuits with a 401.

Register and Guard

@Module({
  imports: [PassportModule],
  providers: [AuthService, LocalStrategy],
})
export class AuthModule {}

Now use AuthGuard from @nestjs/passport to invoke the strategy. The string argument matches the strategy name (defaults are 'local', 'jwt', 'google', etc.).

@Controller('auth')
export class AuthController {
  @Post('login')
  @UseGuards(AuthGuard('local'))
  login(@Request() req) {
    return req.user; // populated by LocalStrategy.validate
  }
}

That’s the entire shape. Every strategy you’ll use — JWT, OAuth, SAML — is the same three pieces: subclass, register, guard.

A Tip: Name Your Guards

AuthGuard('local') works but is stringly typed. A tiny wrapper helps:

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}

@UseGuards(LocalAuthGuard)

You’ll also find it easier to override handleRequest later when you need to customize the 401 response or thread extra context through.

JWT Authentication →