Reputation: 75
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
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 an
UnauthorizedException`. 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;
}
}
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;
}
}
Upvotes: 0
Reputation: 70510
You can use a exception filter to catch UnauthorizedException
s 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
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