Skip to main content
Practice Problems

How to implement authentication with Passport in NestJS?

Authentication in NestJS with Passport

NestJS integrates seamlessly with Passport.js — the most popular Node.js authentication library — through the @nestjs/passport package.


Setup

bash
npm install @nestjs/passport passport passport-local passport-jwt npm install @nestjs/jwt npm install --save-dev @types/passport-local @types/passport-jwt

JWT Strategy (Most Common for APIs)

1. Auth Module

typescript
@Module({ imports: [ PassportModule, JwtModule.register({ secret: process.env.JWT_SECRET, signOptions: { expiresIn: '1h' }, }), UsersModule, ], providers: [AuthService, JwtStrategy, LocalStrategy], controllers: [AuthController], }) export class AuthModule {}

2. Local Strategy (Login)

typescript
import { Strategy } from 'passport-local'; import { PassportStrategy } from '@nestjs/passport'; @Injectable() export class LocalStrategy extends PassportStrategy(Strategy) { constructor(private authService: AuthService) { super({ usernameField: 'email' }); } async validate(email: string, password: string): Promise<User> { const user = await this.authService.validateUser(email, password); if (!user) { throw new UnauthorizedException('Invalid credentials'); } return user; } }

3. JWT Strategy (Protect Routes)

typescript
import { ExtractJwt, Strategy } from 'passport-jwt'; import { PassportStrategy } from '@nestjs/passport'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: process.env.JWT_SECRET, }); } async validate(payload: { sub: string; email: string }) { return { id: payload.sub, email: payload.email }; } }

4. Auth Service

typescript
@Injectable() export class AuthService { constructor( private usersService: UsersService, private jwtService: JwtService, ) {} async validateUser(email: string, password: string) { const user = await this.usersService.findByEmail(email); if (user && await bcrypt.compare(password, user.password)) { const { password, ...result } = user; return result; } return null; } async login(user: User) { const payload = { sub: user.id, email: user.email }; return { access_token: this.jwtService.sign(payload), refresh_token: this.jwtService.sign(payload, { expiresIn: '7d' }), }; } async refreshToken(token: string) { const payload = this.jwtService.verify(token); const newPayload = { sub: payload.sub, email: payload.email }; return { access_token: this.jwtService.sign(newPayload), }; } }

5. Auth Controller

typescript
@Controller('auth') export class AuthController { constructor(private authService: AuthService) {} @UseGuards(AuthGuard('local')) @Post('login') async login(@Request() req) { return this.authService.login(req.user); } @UseGuards(AuthGuard('jwt')) @Get('profile') getProfile(@Request() req) { return req.user; } @Post('refresh') async refresh(@Body('refresh_token') token: string) { return this.authService.refreshToken(token); } }

Global JWT Guard

typescript
// jwt-auth.guard.ts @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { constructor(private reflector: Reflector) { super(); } canActivate(context: ExecutionContext) { const isPublic = this.reflector.getAllAndOverride<boolean>('isPublic', [ context.getHandler(), context.getClass(), ]); if (isPublic) return true; return super.canActivate(context); } }
typescript
// app.module.ts — apply globally @Module({ providers: [ { provide: APP_GUARD, useClass: JwtAuthGuard }, ], }) export class AppModule {}

Now use @Public() decorator to skip auth:

typescript
@Controller('health') export class HealthController { @Public() @Get() check() { return { status: 'ok' }; } }

Flow Summary

Login: POST /auth/login → LocalStrategy.validate() → AuthService.login() → JWT token Request: GET /api/protected Header: Authorization: Bearer <token> → JwtStrategy.validate() → req.user populated → Controller

Best practice: Use JWT for stateless API authentication. Implement refresh tokens with rotation. Store tokens in httpOnly cookies for web apps. Apply JwtAuthGuard globally and use @Public() for open routes.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems