In NestJS, implementing multiple passport-jwt authentication strategies typically involves defining several strategies, each with distinct validation rules or using different JWT keys. Here is a step-by-step guide to achieve this, along with an example:
Step 1: Install Required Packages
First, install Passport, passport-jwt, and @nestjs/passport.
bashnpm install @nestjs/passport passport passport-jwt
Step 2: Create JWT Strategies
In the src/auth/strategies folder, create two files corresponding to different JWT strategies.
For example:
jwt.strategy.ts(default strategy)jwt-admin.strategy.ts(strategy for administrators)
Each file extends the PassportStrategy class and defines different secrets or validation options in the constructor.
Step 3: Define Strategies
In each strategy file, define a class that inherits from PassportStrategy and provides a unique name for each strategy.
For example:
jwt.strategy.ts:
typescriptimport { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy, ExtractJwt } from 'passport-jwt'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: process.env.JWT_SECRET, }); } async validate(payload: any) { return { userId: payload.sub, username: payload.username }; } }
jwt-admin.strategy.ts:
typescriptimport { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy, ExtractJwt } from 'passport-jwt'; @Injectable() export class JwtAdminStrategy extends PassportStrategy(Strategy, 'jwt-admin') { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: process.env.JWT_ADMIN_SECRET, passReqToCallback: true, }); } async validate(req: Request, payload: any) { if (req.url.startsWith('/admin')) { return { adminId: payload.sub, adminName: payload.username }; } return null; } }
Note that in JwtAdminStrategy, passReqToCallback: true enables access to the req object within the validate method.
Step 4: Register Strategies
In the AuthModule, register your strategies using the @Module() decorator. Ensure the strategies are imported and added to the providers array.
typescriptimport { Module } from '@nestjs/common'; import { JwtStrategy } from './strategies/jwt.strategy'; import { JwtAdminStrategy } from './strategies/jwt-admin.strategy'; @Module({ // ... providers: [JwtStrategy, JwtAdminStrategy], // ... }) export class AuthModule {}
Step 5: Use Strategies in Controllers
In your controllers, activate specific strategies using the @UseGuards() decorator.
typescriptimport { Controller, Get, UseGuards } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @Controller('api') export class ApiController { @Get('user') @UseGuards(AuthGuard('jwt')) getUserProfile() { // User endpoint logic } @Get('admin') @UseGuards(AuthGuard('jwt-admin')) getAdminProfile() { // Admin endpoint logic } }
In the example above, accessing /api/user authenticates using the default JWT strategy, while accessing /api/admin uses the admin JWT strategy.
Notes
- Ensure environment variables
JWT_SECRETandJWT_ADMIN_SECRETare set with distinct keys for user JWT and admin JWT respectively. - In the
validatemethod, return a payload object that will be attached to theuserproperty of the request object. - For specific validation logic, such as verifying admin permissions, perform these checks within the
validatemethod.
In summary, NestJS and Passport provide flexible ways to define and use multiple authentication strategies, enabling you to protect your API based on different business scenarios.