Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NestJS custom PassportStrategy not registered when shared through library

I've been tasked with isolating our NestJS authentication module into a separate shared library, in order for it to be reused between multiple NestJS projects. Each project lives in each own repository and the shared library is imported as an npm package. I'm using NestJS' passport module for the authentication (using jwt tokens) and have basically just followed the official documentation on how to implement it.

I've followed the pattern of other NestJS community packages, and so far I've moved most of the authentication code over and made sure it could compile and run.

Now, I've come across an issue. The application no longer recognizes the custom jwt passport strategy, after I moved it over to the library and I have no idea why. I just get the exception:

Unknown authentication strategy "jwt"

Example:

This is the custom passport strategy and the AuthModule (the real version is more complex, but this is a minimal reproduceable example). The code is exactly the same in both the "parent"-project and the new library-project.

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

@Injectable()
export class CustomStrategy extends PassportStrategy(Strategy, 'custom') {
  async validate(request: Request): Promise<any> {
    console.log('Custom validation', request);

    return true;
  }
}

@Module({})
export class AuthModule {
  static forRoot() {
    return {
      module: AuthModule,
      providers: [CustomStrategy],
      exports: [CustomStrategy],
    };
  }
}

This is how I register it in the NestJS application:

import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { AuthModule } from '@my-org/common';        // Library version
// import { AuthModule } from './auth/AuthModule';  // Local version

@Module({
  imports: [
    AuthModule.forRoot(),
    PassportModule.register({ defaultStrategy: 'custom' })
  ]
})
export class CommonModule {}

export class CustomAuthGuard extends AuthGuard('custom') {}

When the AuthModule is refererenced from within the same NestJS project, everything runs and I get the Custom validation console message.

When the AuthModule is imported from my npm library, I get the Unknown authentication strategy "custom" exception from passport, whenever I make a request.

The code on both sides is exactly the same. The usage of the module is exactly the same, regardless of where the module comes from. The shared library is set up using the same pattern as official NestJS packages, such as @nestjs/common and @nestjs/cqrs. Any other registered services exported by the library works as intended (I can include another minimal example to show this if requested).

What am I missing? How can I share my custom NestJS PassportStrategy using a separate npm package?

I've spent half my workday trying to solve this issue, and so far I think it might have something to do with which passport instance the strategy is registered with, but I don't know how to test this - or, if that is even the case, how to solve it.

like image 387
Nikolaj Dam Larsen Avatar asked Jan 18 '21 21:01

Nikolaj Dam Larsen


People also ask

How do I create a custom passport strategy?

Configure Strategy The custom authentication strategy authenticates users by custom logic of your choosing. The strategy requires a verify callback, which is where the custom logic goes and calls done providing a user. Note that, req is always passed as the first parameter to the verify callback.

What is passport in Nestjs?

Passport is the most popular node.js authentication library, well-known by the community and successfully used in many production applications. It's straightforward to integrate this library with a Nest application using the @nestjs/passport module.

What is JWT in Nestjs?

JWT or JSON Web Token is an industry standard RFC 7519 method for representing claims securely between two parties. Passport is the most popular Node authentication library, well-known by the community and successfully used in many production application, NestJS has supported it outside the box with @nestjs/passport.


1 Answers

Strategy:

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

@Injectable()
export class CustomStrategy extends PassportStrategy(Strategy, "custom") {
    static key = "custom"

    async validate(req: Request): Promise<User> {
        const valid = true;
        if(!valid) throw new UnauthorizedException();
        return {id: "123", name: "test"};
    }
}

Auth Module:

@Module({
  imports: [PassportModule],
  providers: [CustomStrategy]
})
export class AuthModule {}

Controller Decorator:

@UseGuards(AuthGuard(CustomStrategy.key))
like image 112
Mathis Michel Avatar answered Dec 31 '22 10:12

Mathis Michel