How to get access to JwtToken to check with blacklist within nestjs passport strategy?

1.5k Views Asked by At

I'm trying to check for blacklisted JWT tokens within JWTStrategy. jwtFromRequest doesn't take an async function, so I can't check it there.

validate function gives access to JWT payload and not the token.

Below is my sample code.

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    private readonly configService: ConfigService<AppJWTSettings>,
    @Inject(CACHE_MANAGER) private readonly cache: Cache,
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // Returns the encoded JWT string or null.
      ignoreExpiration: false, // validate the expiration of the token.
      // https://docs.nestjs.com/techniques/authentication#implementing-passport-jwt
      // PEM-encoded public key
      secretOrKey: configService.get<string>('JWT_PUBLIC_KEY'),
      algorithms: ['RS256'],
    });
  }

  /**
   * Passport will build a user object based on the return value of our validate() method,
   * and attach it as a property on the Request object.
   *
   * @param payload JWT payload
   */
  async validate(payload: JwtPayload): Promise<JwtUser> {
    const user = { id: payload.sub, iat: payload.iat };
    return user;
  }
}
2

There are 2 best solutions below

2
On

When a new token is created, I store the token in a cookie and pass the token via AJAX calls and sometimes pass it around via query string requests. You should just be able to pass whatever token the user is using via cookies (headers), query string etc... On the controller, have it validated, if blacklisted return a redirect url or string on unauthorized and redirect via JavaScript.

0
On

There is one option with secretOrKeyProvider. Here is an example:

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    private readonly configService: ConfigService<AppJWTSettings>,
    @Inject(CACHE_MANAGER) private readonly cache: Cache,
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // Returns the encoded JWT string or null.
      ignoreExpiration: false, // validate the expiration of the token.
      // https://docs.nestjs.com/techniques/authentication#implementing-passport-jwt
      // PEM-encoded public key
      secretOrKeyProvider: (
        _request: Request,
        rawJwtToken: any,
        done: (err: any, secretOrKey?: string | Buffer) => void,
      ) => {
        // Check if your token is blocked here!!!
        void isBlocked(rawJwtToken).then(isBlocked => {
          if (isBlocked) {
            done(new Error("This token is blocked"));
          } else {
            done(null, configService.get<string>('JWT_PUBLIC_KEY'));
          }
        });
      },
      algorithms: ['RS256'],
    });
  }

  /**
   * Passport will build a user object based on the return value of our validate() method,
   * and attach it as a property on the Request object.
   *
   * @param payload JWT payload
   */
  async validate(payload: JwtPayload): Promise<JwtUser> {
    const user = { id: payload.sub, iat: payload.iat };
    return user;
  }
}