← Back to list

Simple and stateless JWT authentication flow in NestJS

Step 1: Install Dependencies

Thilrash Ameen · 2026-05-22 09:31 · 2 claps · 2.0 min read
#angular #nestjs #jwt #software-development #software-engineering
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Simple and stateless JWT authentication flow in NestJS

Step 1: Install Dependencies

You’ll need the NestJS wrappers for Passport and JWT, along with the underlying Passport strategies.

npm install @nestjs/passport @nestjs/jwt passport passport-jwt
npm install -D @types/passport-jwt

Step 2: Configure the Auth Module

The AuthModule is where we configure how tokens will be signed. In a real application, you should use environment variables for your secret key.

// auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [
    PassportModule,
    JwtModule.register({
      secret: process.env.JWT_SECRET || 'super-secret-key',
      signOptions: { expiresIn: '1h' }, // Tokens expire in 1 hour
    }),
  ],
  providers: [AuthService, JwtStrategy],
  controllers: [AuthController],
})
export class AuthModule {}

Step 3: Implement the Auth Service

The AuthService is responsible for generating the JWT when a user successfully logs in.

// auth.service.ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
  constructor(private jwtService: JwtService) {}

  // In a real app, you would validate the password against the DB first
  async login(user: any) {
    const payload = { email: user.email, sub: user.id };

    return {
      access_token: this.jwtService.sign(payload),
    };
  }
}

Step 4: Create the JWT Strategy

The Strategy acts as a middleware. It intercepts incoming requests, extracts the JWT from the Authorization: Bearer header, verifies the signature, and decodes the payload.

// jwt.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: process.env.JWT_SECRET || 'super-secret-key',
    });
  }

  // This method runs ONLY if the token is valid and unexpired
  async validate(payload: any) {
    // What you return here is injected into the request object as `req.user`
    return { userId: payload.sub, email: payload.email };
  }
}

Step 5: Set Up the Auth Guard

Guards are the NestJS abstraction for protecting routes. Instead of typing @UseGuards(AuthGuard(‘jwt’)) everywhere, it is cleaner to create a custom class.

 // jwt-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}

Step 6: Protect Your Routes

Finally, tie it all together in your controller. We’ll simulate a login route to issue the token, and a protected route that requires it.

// auth.controller.ts
import { Controller, Post, Get, Body, Request, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { JwtAuthGuard } from './jwt-auth.guard';

@Controller('auth')
export class AuthController {
  constructor(private authService: AuthService) {}

  @Post('login')
  async login(@Body() loginDto: Record<string, any>) {
    // Mock user verification — replace with your DB logic
    const user = { id: 1, email: loginDto.email }; 
    return this.authService.login(user);
  }

  @UseGuards(JwtAuthGuard)
  @Get('profile')
  getProfile(@Request() req) {
    // req.user is populated by the return value of JwtStrategy.validate()
    return req.user; 
  }
}

Security Note: JWTs are stateless, meaning a stolen token cannot easily be invalidated before it expires. Keep your expiresIn time relatively short (e.g., 15 minutes to 1 hour).


메타데이터
post_id
7d9048ed072c
slug
simple-and-stateless-jwt-authentication-flow-in-nestjs-7d9048ed072c
url
https://medium.com/@ameenthilrash/simple-and-stateless-jwt-authentication-flow-in-nestjs-7d9048ed072c
canonical_url
https://medium.com/@ameenthilrash/simple-and-stateless-jwt-authentication-flow-in-nestjs-7d9048ed072c
author_url
https://medium.com/@ameenthilrash
status
ok
fetched_at
2026-06-09 15:37:30