Nest: How to implement multiple JWT strategies with Passport in V5

Created on 18 May 2018  路  6Comments  路  Source: nestjs/nest

I'm submitting a...


[ ] Regression
[ ] Bug report
[ ] Feature request
[X] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

Previously we would declare the strategy type (string) to utilise in the passport.authenticate method (e.g. passport.authenticate('jwt-1', ...)) where 'jwt-1' was previously declared in the JwtStrategy class via passport.use('jwt-1')

Expected behavior

Expect that I can export multiple JwtStrategy classes and use them according to the route

Minimal reproduction of the problem with instructions

Compare JwtStrategy method in v4 to v5 - can no longer define a custom type string.

What is the motivation / use case for changing the behavior?

Example:

  • application utilises two-factor authentication
  • user login with user/pass server returns a JWT without two-factor acknowledgement
  • user must then verify with two-factor code
  • the verification route should guard with a JWT that excludes two-factor verification
  • after verification, all future routes should guard with a JWT that includes two-factor auth

Nest version: 5
3rd-party 馃殌 type

Most helpful comment

@jekirl the workaround is to follow the pre-nest v5 authentication/passport guide

Its methods still appear to work but you cannot take advantage of the new AuthGuard decorators by route.

Create your jwt strategy classes and define their name in the passport.use() call:

@Injectable()
export class JwtMfaStrategy extends Strategy {
  constructor(private authService: AuthService) {
    super(
      jwtOptions,
      async (req, payload, next) => await verify(this.authService, req, payload, next),
    );
    passport.use('jwt-mfa', this);
  }
}

Import the strategies into an AuthModule where you define which strategy/route they apply to via consumer middleware:

@Module({
  imports: [],
  providers: [AuthService, JwtStrategy, JwtMfaStrategy],
  controllers: [],
  exports: [AuthService]
})
export class AuthModule implements NestModule {
  public configure(consumer: MiddlewareConsumer) {
    consumer.apply(passport.authenticate('jwt', { session: false })).forRoutes('/some-route');
    consumer
      .apply(passport.authenticate('jwt-mfa', { session: false }))
      .forRoutes('/another-route');
  }
}

All 6 comments

Is there a workaround for this regression?

@jekirl the workaround is to follow the pre-nest v5 authentication/passport guide

Its methods still appear to work but you cannot take advantage of the new AuthGuard decorators by route.

Create your jwt strategy classes and define their name in the passport.use() call:

@Injectable()
export class JwtMfaStrategy extends Strategy {
  constructor(private authService: AuthService) {
    super(
      jwtOptions,
      async (req, payload, next) => await verify(this.authService, req, payload, next),
    );
    passport.use('jwt-mfa', this);
  }
}

Import the strategies into an AuthModule where you define which strategy/route they apply to via consumer middleware:

@Module({
  imports: [],
  providers: [AuthService, JwtStrategy, JwtMfaStrategy],
  controllers: [],
  exports: [AuthService]
})
export class AuthModule implements NestModule {
  public configure(consumer: MiddlewareConsumer) {
    consumer.apply(passport.authenticate('jwt', { session: false })).forRoutes('/some-route');
    consumer
      .apply(passport.authenticate('jwt-mfa', { session: false }))
      .forRoutes('/another-route');
  }
}

Thanks @danielkerwin

Edit: turns out it was fixed by using allowSyntheticDefaultImports: false somehow...
I got that sort of working following this sample However I am now seeing e2e testing fail on the passport.use lines
Cannot set property 'facebook' of undefined

Should I make a new issue for this?

I would also need this feature -- in my case I want to have two types of tokens for two purposes, for security signed with different keys. It would be nice to just build two strategies and use something like

@UseGuards(AuthGuard('jwt', { strategy: ... /* name, or maybe class? */ }))

See https://docs.nestjs.com/techniques/authentication (Multiple Strategies chapter)

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cojack picture cojack  路  3Comments

rafal-rudnicki picture rafal-rudnicki  路  3Comments

JulianBiermann picture JulianBiermann  路  3Comments

FranciZ picture FranciZ  路  3Comments

menme95 picture menme95  路  3Comments