Skip to Content

Plug-and-Play Authentication in Node.js with JWT & NestJS

Creating a plug-and-play authentication system in NestJS means building a module that is:

  • Self-contained
  • Reusable across multiple apps or microservices
  • Easy to configure (e.g., JWT secret, user model)
  • Extendable (e.g., social login or OTP)

Let’s walk through this step by step with real-world logic explanations for each part.

Here we are not using any database connections or any custom logics, this is a basic setup where we can enhance it to meet the business needs.

1. Module Structure

auth/

├── auth.module.ts

├── auth.service.ts

├── auth.controller.ts

├── jwt.strategy.ts

├── local.strategy.ts

├── guards/

│   └── jwt-auth.guard.ts

├── dto/

│   └── login.dto.ts

├── interfaces/

│   └── user.interface.ts

Your Dynamic Snippet will be displayed here... This message is displayed because you did not provided both a filter and a template to use.


2. JWT-Based Plug-and-Play Auth

auth.module.ts

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

@Module({
  imports: [
    PassportModule,
    JwtModule.register({
      secret: 'your-secret-key', // Plug: you can use config service to pull this dynamically
      signOptions: { expiresIn: '1h' },
    }),
  ],
  controllers: [AuthController],
  providers: [AuthService, JwtStrategy],
  exports: [AuthService],
})
export class AuthModule {}

Explanation:

  • PassportModule allows plugging in various strategies (JWT, local, Google).
  • JwtModule​ registers the signing logic.
  • JwtStrategy​ handles decoding and validating the token on each request.

auth.service.ts

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

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

  async validateUser(username: string, password: string) {
    // Example plug: Replace this with your real DB logic
    if (username === 'admin' && password === 'admin123') {
      return { userId: 1, username: 'admin' };
    }
    return null;
  }

  async login(user: any) {
    const payload = { username: user.username, sub: user.userId };
    return {
      access_token: this.jwtService.sign(payload),
    };
  }
}

Explanation:

  • validateUser()​ is where you hook your own DB or user service.
  • login()​ creates the JWT token from the payload.

auth.controller.ts

import { Controller, Post, Body, UseGuards, Request } from '@nestjs/common';
import { AuthService } from './auth.service';

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

  @Post('login')
  async login(@Body() body: { username: string, password: string }) {
    const user = await this.authService.validateUser(body.username, body.password);
    if (!user) throw new Error('Invalid credentials');
    return this.authService.login(user);
  }
}

Explanation:

  • /auth/login accepts credentials and returns a signed JWT.
  • This is a clean API endpoint that can be dropped into any NestJS app.

jwt.strategy.ts

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

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: 'your-secret-key', // Same key used for signing
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

Explanation:

  • Extracts token from Authorization header.
  • Validates the token and attaches the payload to request.user.

jwt-auth.guard.ts

import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

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

Explanation:

  • A simple wrapper to secure routes using JWT.

3. Securing Routes in Other Modules

any.controller.ts

import { Controller, Get, UseGuards, Request } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';

@Controller('profile')
export class ProfileController {
  @UseGuards(JwtAuthGuard)
  @Get()
  getProfile(@Request() req) {
    return req.user;
  }
}

Explanation:

  • This route requires a valid JWT in the header.
  • Returns the decoded user info (in real case, fetch from DB).


This is a simple POC plug and play auth made in nestjs. For the more customization keep adding the business flow.


Hope you find it helpful!

Migrate S3 storage to Azure Blog container