oauth2orize icon indicating copy to clipboard operation
oauth2orize copied to clipboard

Authorization Code redirect call in case of error

Open simionrobert opened this issue 4 years ago • 2 comments

Is there a mechanism to send to the redirect_uri some custom query parameters in case of error? (I'm talking about https://localhost:8080/oauth2/authorize/decision endpoint)

Expected behavior

In case there is an error on

server.grant(oauth2orize.grant.code((client, redirectUri, user, ares, done) => {...});

it should call the redirect_uri with an error description as a query parameter.

Actual behavior

Instead, a json response containing the error description is returned.

{"error":"server_error","error_description":"The database service encountered an unexpected error."}

simionrobert avatar Feb 03 '20 21:02 simionrobert

What error handling middleware is being used on that endpoint?

jaredhanson avatar Feb 04 '20 00:02 jaredhanson

Thank you for responding.

The code I use is this. However, the error handler I wrote at the end is not called in case of error. I think the error handling is done internally, or I did not specify one? Can you help me with a solution to this?

//////////////////////////////oauth2.js/////////////////////////
server.exchange(oauth2orize.exchange.code((client, code, redirectUri, done) => {

  // This code can either be for service/credential authorization. It should be found by value
  Code.findOne({ value: code, client_id: client._id }, function (err, authCode) {
    if (err) { return done(err); }
    if (authCode === undefined || authCode === null) { return done(errors.internalServerError); }
    if (client._id.toString() !== authCode.client_id) { return done(errors.invalidClientId); }
    if (redirectUri !== authCode.redirect_uri) { return done(errors.notMatchRedirectUri); }

    // check token availability
    if (authCode.creation_date.getTime() + 1000 * config.settings.code_expiring_time < Date.now()) { return done(errors.invalidCode, false); }

    switch (authCode.scope) {
      case 'service':
        crypto.randomBytes(256, function (err, buffer) {
          if (err) return done(errors.internalServerError);

          const tokenValue = buffer.toString('hex');

          Token.updateOne({ client_id: authCode.client_id, type: 'access_token' }, {
            value: tokenValue,
            type: 'access_token',
            user_id: authCode.user_id,
            client_id: authCode.client_id
          }, { upsert: true }, (err) => {
            if (err) return done(errors.databaseError);

            done(null, tokenValue, { token_type: "Bearer", expiresIn: config.settings.csc.access_token_expiring_time });
          });
        });
        break;

      case 'credential':
        //generate SAD. It gets deleted when the signature is done
        crypto.randomBytes(128, function (err, buffer) {
          if (err) return done(errors.internalServerError);

          const sadValue = buffer.toString('hex');
          const sad = new Sad({
            value: sadValue,
            hashes: authCode.hashes,
            credential_id: authCode.credential_id
          });

          sad.save((err) => {
            if (err) return done(errors.databaseError);

            // send response
            done(null, sadValue, { token_type: "SAD", expiresIn: config.settings.csc.sad_expiring_time });
          });
        });
        break;
      default:
        done(errors.internalServerError);
    }
  });
}));

module.exports.decision = [
  login.ensureLoggedIn(),
  server.decision(function (req, done) {
    return done(null, {
      scope: req.oauth2.req.scope,
      credentialID: req.body.credentialID,
      hash: req.body.hash,
      numSignatures: +req.body.num_signatures
    }) // this is ares
  }) // invokes server.grant()
];

//////////////////app.js////////////////////
app.post(`/oauth2/authorize/decision`, require('./routes/oauth2').decision);


// error handler
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};
  req.app.get('env') === 'development' ? logger.info(err) : {};

  // render the error page
  if (err.status !== undefined) {
    res.status(err.status);
    return res.json({
      error: err.message,
      error_description: err.description
    });
  }

  // fallback for unknown application errors
  res.status(errors.internalServerError.status);
  res.json({
    error: errors.internalServerError.message,
    error_description: errors.internalServerError.description
  });
});

simionrobert avatar Feb 04 '20 08:02 simionrobert