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.
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.