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!

ZHOST May 14, 2025
Share this post
Migrate S3 storage to Azure Blog container