0
0
NestjsHow-ToBeginner ยท 4 min read

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 JwtModule and JwtStrategy.
  • 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

ConceptDescription
JwtModule.registerConfigure JWT with secret and expiration
JwtStrategyValidate 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.