I wrote a custom JWT guard from which I am throwing an error if I find that an access token is missing from the a request cookie.
Problem is, I want to return an UnauthorizedException
with a custom message to my React client, instead of ForbiddenException
which is now being returned.
What is the correct way to throw and catch an exception from a guard in a filter? Or is there a better approach?
I am following this suggestion
JwtAuthGuard.ts
const cookieExtractor = (req: Request) => {
if (req && req.cookies) {
return req.cookies['jwt'];
}
};
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
private logger = new Logger(JwtAuthGuard.name);
constructor() {
super();
}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
try {
const accessToken = ExtractJwt.fromExtractors([cookieExtractor])(request);
if (!accessToken)
throw new UnauthorizedException('Access token is not set');
return this.activate(context);
} catch (err) {
this.logger.error((err as Error).message);
return false;
}
}
async activate(context: ExecutionContext): Promise<boolean> {
return super.canActivate(context) as Promise<boolean>;
}
}
AuthExceptionFilter.ts
@Catch(HttpException)
export class AuthExceptionFilter extends BaseExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
console.log('exception', exception);
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
super.catch(exception, host);
}
}
Controller.ts
@Get('/status')
@UseGuards(JwtAuthGuard)
@UseFilters(AuthExceptionFilter)
async status(@Req() req: Request) {
return true;
}
exception from filter's console.log
[Nest] 65933 - 02/24/2023, 10:44:38 AM ERROR [JwtAuthGuard] Access token is not set
exception ForbiddenException: Forbidden resource
at canActivateFn (/test-project/node_modules/@nestjs/core/router/router-execution-context.js:136:23)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at /test-project/node_modules/@nestjs/core/router/router-execution-context.js:42:31
at /test-project/node_modules/@nestjs/core/router/router-proxy.js:9:17 {
response: {
statusCode: 403,
message: 'Forbidden resource',
error: 'Forbidden'
},
status: 403,
options: {}
}