Prémices K
Prémices K

Reputation: 75

Customise the response on verification failure for a jwt Strategy NestJs

I successfully implemented a jwt strategy for authentication using nestJs.

Below is the code for the jwt strategy

import { ServerResponse } from './../helpers/serverResponse.helper';
import { Injectable, UnauthorizedException, HttpStatus } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { config as env } from 'dotenv';
import { Bugsnag } from '../helpers/bugsnag.helper';

env();

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
    constructor(
    private readonly logger: Bugsnag,
    ) {
    super({
        jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
        secretOrKey: process.env.JWT_SECRET_KEY,
        passReqToCallback: true,
    });

    }

    async validate(payload, done: Function) {
    try {
        const validClaims = await this.authService.verifyTokenClaims(payload);

        if (!validClaims)
            return done(new UnauthorizedException('invalid token claims'), false);
        done(null, payload);
    } catch (err) {
        this.logger.notify(err);
        return ServerResponse.throwError({
        success: false,
        status: HttpStatus.INTERNAL_SERVER_ERROR,
        message: 'JwtStrategy class, validate function',
        errors: [err],
        });
    }
    }
}

I saw here that the validate function will be called only when a valid token was provided in the request headers and I'm okay with that. However, I would like to know if it is possible to customize the response object which is sent in that case (invalid token provided).

If yes, how do I do that ?

Upvotes: 6

Views: 5919

Answers (3)

lang sun
lang sun

Reputation: 46

The idea of how I return the error information back to the endpoint point is pretty much the same as the first answer. The difference is I wrap the error message from either err infointo anUnauthorizedException`. The return values to the endpoint will be as follows.


... import dependencies

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  ...
  handleRequest(err, user, info) {
    if (!user) {
      throw new UnauthorizedException(err || info);
    }
    return user;
  }
}

enter image description here

Another thing that needs to be mentioned is that the error will only be thrown in the backend when you throw the err or info directly instead of wrapping them in the Exception. The return value to the endpoint will be 500 internal error which is obviously not friendly


... import dependencies

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  ...
  handleRequest(err, user, info) {
    if (!user) {
      throw err || info;
    }
    return user;
  }
}

enter image description here

Upvotes: 0

Jay McDoniel
Jay McDoniel

Reputation: 70510

You can use a exception filter to catch UnauthorizedExceptions and modify the response there if you'd like. The other option would be extending the AuthGuard('jwt') mixin class and adding in some logic around a try/catch for the super.canActivate(context), then in the error read what the reason is and throw a specific UnauthorizedException with your custom message

Upvotes: 5

Gyanendro Kh
Gyanendro Kh

Reputation: 405

You can use the AuthGuard('jwt')'s handleRequest method to throw any exception on JWT Validation failure.

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  handleRequest(err: any, user: any, info: any, context: any, status: any) {
    if (info instanceof JsonWebTokenError) {
      throw new UnauthorizedException('Invalid Token!');
    }

    return super.handleRequest(err, user, info, context, status);
  }
}

JsonWebTokenError comes from jsonwebtoken library, which is used internally by passport.

Upvotes: 6

Related Questions