How to Use JWT in NestJS for Authentication
In NestJS, use the
@nestjs/jwt package along with @nestjs/passport to implement JWT authentication. Register JwtModule with a secret key, create a strategy extending PassportStrategy, and protect routes with @UseGuards(AuthGuard('jwt')).Syntax
To use JWT in NestJS, you need to import and configure the JwtModule with a secret key and expiration time. Then create a JWT strategy by extending PassportStrategy with the jwt strategy. Protect routes using @UseGuards(AuthGuard('jwt')) to require a valid token.
JwtModule.register({ secret, signOptions }): Configures JWT settings.PassportStrategy(Strategy): Base class to create JWT validation logic.@UseGuards(AuthGuard('jwt')): Secures routes with JWT authentication.
typescript
import { JwtModule } from '@nestjs/jwt'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy, ExtractJwt } from 'passport-jwt'; import { Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; // JwtModule setup JwtModule.register({ secret: 'yourSecretKey', signOptions: { expiresIn: '60s' }, }); // JWT Strategy @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: 'yourSecretKey', }); } async validate(payload: any) { return { userId: payload.sub, username: payload.username }; } } // Protecting routes @UseGuards(AuthGuard('jwt')) async someProtectedRoute() { // logic here }
Example
This example shows a simple NestJS module that sets up JWT authentication. It includes a login endpoint that signs a token and a protected route that requires a valid JWT.
typescript
import { Module, Controller, Post, Request, UseGuards, Get, Injectable } from '@nestjs/common'; import { JwtModule, JwtService } from '@nestjs/jwt'; import { PassportModule } from '@nestjs/passport'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy, ExtractJwt } from 'passport-jwt'; import { AuthGuard } from '@nestjs/passport'; @Injectable() class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: 'secretKey123', }); } async validate(payload: any) { return { userId: payload.sub, username: payload.username }; } } @Controller() class AppController { constructor(private jwtService: JwtService) {} @Post('login') login(@Request() req) { // Normally validate user here const payload = { username: 'john', sub: 1 }; return { access_token: this.jwtService.sign(payload), }; } @UseGuards(AuthGuard('jwt')) @Get('protected') getProtected(@Request() req) { return { message: 'This is protected', user: req.user }; } } @Module({ imports: [ PassportModule, JwtModule.register({ secret: 'secretKey123', signOptions: { expiresIn: '1h' }, }), ], controllers: [AppController], providers: [JwtStrategy], }) export class AppModule {}
Output
{
"access_token": "<JWT token string>"
}
// When calling GET /protected with Authorization: Bearer <token>
{
"message": "This is protected",
"user": {
"userId": 1,
"username": "john"
}
}
Common Pitfalls
Common mistakes when using JWT in NestJS include:
- Not setting the same secret key in both
JwtModuleandJwtStrategy. - Forgetting to extract the token from the Authorization header correctly.
- Not protecting routes with
@UseGuards(AuthGuard('jwt')), leaving them open. - Ignoring token expiration, which causes valid tokens to be rejected.
Always ensure your secret is secure and never hardcode it in production.
typescript
/* Wrong: Different secrets */ JwtModule.register({ secret: 'secret1' }); @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: 'secret2' }); // Mismatch causes auth failure } } /* Right: Use same secret */ const secret = 'mySecret'; JwtModule.register({ secret }); @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: secret }); } }
Quick Reference
| Concept | Description |
|---|---|
| JwtModule.register | Configure JWT with secret and expiration |
| JwtStrategy | Validate JWT payload and user info |
| AuthGuard('jwt') | Protect routes requiring JWT authentication |
| JwtService.sign(payload) | Create a JWT token with payload |
| ExtractJwt.fromAuthHeaderAsBearerToken() | Extract token from Authorization header |
Key Takeaways
Use JwtModule with a consistent secret key for signing and verifying tokens.
Create a JwtStrategy extending PassportStrategy to validate JWT payloads.
Protect routes with @UseGuards(AuthGuard('jwt')) to require authentication.
Always extract JWT from the Authorization header as a Bearer token.
Handle token expiration properly to avoid unauthorized access.