How to set a custom unauthorized oauth2 error using NestJS and Passport

Viewed 1126

I am using a custom passport strategy and I would like to send to the client a custom error If the client denies access to the oauth2 application.

This is the authorization flow:

enter image description here

I would like to send the user a customized error message instead of the 500 error. In case of success, when the user authorizes the application everything goes well.

In the documentation NestJS official documentation there is an example of how I could do this: https://docs.nestjs.com/security/authentication#extending-guards

import {
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  canActivate(context: ExecutionContext) {
    // Add your custom authentication logic here
    // for example, call super.logIn(request) to establish a session.
    return super.canActivate(context);
  }

  handleRequest(err, user, info) {
    // You can throw an exception based on either "info" or "err" arguments
    if (err || !user) {
      throw err || new UnauthorizedException();
    }
    return user;
  }
}

There is no apparent change and when I analyze the application logs, the only thing that is different is that it raises an exception:

api_1         | [Nest] 5080   - 12/10/2020, 6:13:54 PM   [RouterExplorer] Mapped {/users/sign-up/email, POST} route +0ms
api_1         | [Nest] 5080   - 12/10/2020, 6:13:54 PM   [RouterExplorer] Mapped {/users/sign-up/confirm-email, GET} route +0ms
api_1         | [Nest] 5080   - 12/10/2020, 6:13:54 PM   [NestApplication] Nest application successfully started +3ms
api_1         | [Nest] 5080   - 12/10/2020, 6:14:00 PM   [ExceptionsHandler] Object:
api_1         | {
api_1         |   "name": "AuthorizationError",
api_1         |   "message": "",
api_1         |   "code": "access-denied",
api_1         |   "status": 500
api_1         | }
api_1         |  +6377ms

These are the relevant codes regarding this problem.

meli.strategy.ts

import { Strategy } from 'passport-oauth2';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';

import UsersService from '@/users/users.service';
import MeliService from '@/meli/meli.service';

@Injectable()
export class MeliStrategy extends PassportStrategy(Strategy, 'meli') {
  constructor(
    private usersService: UsersService,
    private meliService: MeliService,
  ) {
    super({
      authorizationURL: `https://auth.mercadolivre.com.br/authorization?response_type=code&client_id=${process.env.MELI_APP_ID}`,
      tokenURL: 'https://api.mercadolibre.com/oauth/token',
      clientID: process.env.MELI_APP_ID,
      clientSecret: process.env.MELI_APP_SECRET,
      callbackURL: process.env.MELI_REDIRECT_URL,
      scope: 'authorization_code',
    });
  }

  async validate(accessToken: string) {
    const userData = await this.meliService.getUserData(accessToken);
    let user = await this.usersService.findUserByMercadoLibre(userData);

    if (!user) {
      user = await this.usersService.signUpByMercadoLibre(userData);
    }

    return user;
  }
}

export default MeliStrategy;

meli-auth.guard.ts

import {
  BadRequestException,
  ExecutionContext,
  Injectable,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export default class MeliAuthGuard extends AuthGuard('meli') {
  canActivate(context: ExecutionContext) {
    // Add your custom authentication logic here
    // for example, call super.logIn(request) to establish a session.
    return super.canActivate(context);
  }

  handleRequest(err, user, info) {
    // You can throw an exception based on either "info" or "err" arguments
    if (err || !user) {
      throw err || new BadRequestException('Just a custom message...');
    }
    return user;
  }
}
0 Answers
Related