node.jsnestjsnestjs-jwt

NestJs authentication with JWT strategy - add validation option of "ignoreNotBefore"


I am using an AuthGuard in NestJs to validate the requests jwt token. Because of my service is only validate the token and not created it, It must not use the "nbf" validation in order to avoid cases the the time of the server which creates the token is later than my server.

When working with pure node.js using jsonwebtoken library it is easy to add option to turn off this validation by adding:

jwt.verify(token, cert, {ignoreNotBefore: true})

This is working as well. But, how can I do it using nest?

This is my guard:

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

     constructor(private reflector: Reflector,
              private authService: AuthService) {
       super();
     }

     async canActivate(context: ExecutionContext) {
       const isValid = await super.canActivate(context);
       return isValid;
     }

     handleRequest(err, user, info) {
       if (err || !user) {
         Logger.error(`Unauthorized: ${info && info.message}`);
         throw err || new UnauthorizedException();
      }
      return user;
    }
   }

In the JWT strategy, I tried to add the ignoreNotBefore option when calling "super" of PassportStrategy, bur this is not working:

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService,
              private config: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      ignoreNotBefore: true,
      secretOrKey: fs.readFileSync(config.get('auth.secret')),
    });
  }

  validate(payload: any) {
     const isAuthorized = this.authConfig.roles.some((role) => payload.role?.includes(role));
     if(!isAuthorized) {
        Logger.error(`Unauthorized: Invalid role`);
        throw new UnauthorizedException();
    }
    return true;
  }
}

What is the right way to do that?

Thanks.


Solution

  • JwtAuthGuard

    
    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
      constructor(private authService: AuthService,
                  private config: ConfigService) {
        super({
          jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
          ignoreExpiration: false,
          jsonWebTokenOptions: {
            // this object maps to jsonwebtoken verifier options
            ignoreNotBefore: true,
            // ...
            // maybe ignoreExpiration too?
          },
          secretOrKey: fs.readFileSync(config.get('auth.secret')),
        });
      }
    
      validate(payload: any) {
         const isAuthorized = this.authConfig.roles.some((role) => payload.role?.includes(role));
         if(!isAuthorized) {
            Logger.error(`Unauthorized: Invalid role`);
            throw new UnauthorizedException();
        }
        return true;
      }
    }

    Explanation

    Move your ignoreNotBefore to jsonWebTokenOptions as this object maps to the jsonwebtoken verifier options. This is as Nest.js has wrapped passport-jwt and passport-jwt wraps jsonwebtoken. So options in the root object are mainly configuring the strategy (passport) and not configuring jsonwebtoken (as much).

    Learn More

    1. http://www.passportjs.org/packages/passport-jwt/