Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hint from authorizer which error response to return to the user #659

Closed
2 of 4 tasks
fantapop opened this issue Apr 12, 2020 · 7 comments
Closed
2 of 4 tasks

Hint from authorizer which error response to return to the user #659

fantapop opened this issue Apr 12, 2020 · 7 comments
Labels

Comments

@fantapop
Copy link
Contributor

Our authorizer supports 3 different types of auth. In the case of all auth failing, the promise to resolve last is the one that is returned to the user. For the express route that happens here:

if (responded == security.length && !success) {

This is usually the correct error response. I think the one that is actually being attempted will likely get further in the authentication check than auth methods that can be immediately pruned out, However I've seen the wrong error being shown to our users on a few occasions and its very confusing.

Sorting

  • I'm submitting a ...

    • bug report
    • feature request
    • support request
  • I confirm that I

    • used the search to make sure that a similar issue hasn't already been submit

Expected Behavior

The error related to the intended authentication method will be returned to the user.

Current Behavior

The auth promise that takes the longest to resolve is returned to the user.

Possible Solution

My idea is to allow the authorizer to reject the auth method with some additional information which indicates that it was not attempted by the user. For example if an api supports api key as well as bearer token and a request is made in which the x-api-key header was not passed the authorizer could reject with:

{
    error: new Error("X-Api-Key Header was missing"),
    priority: 2,
}

and

{
    error: new Error("Bearer Token was expired"),
    priority: 1,
}

Context (Environment)

Version of the library: 3.0.4
Version of NodeJS: 12

  • Confirm you were using yarn not npm: [x]

Detailed Description

Breaking change?

This could be made in a way that supports the old way and the new way

@WoH
Copy link
Collaborator

WoH commented Apr 18, 2020

Can you provide some additional info, so we can better understand your use case.
Are you using one Security Decorator here or multiple?
Maybe it's a good idea to have a combined security decorator (if you are using multiple) so you have full control what to return from that one method?

@fantapop
Copy link
Contributor Author

fantapop commented Apr 18, 2020 via email

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days

@fantapop
Copy link
Contributor Author

This one is still biting us every once and a while. I could come up with a backwards compatible POC if you think this would have a possibility of getting merged @WoH

@10ko
Copy link

10ko commented Sep 17, 2020

I was looking around to check if someone has solved this problem and stumbled upon this issue.
@fantapop How did you solve it at the end?

@fantapop
Copy link
Contributor Author

fantapop commented Sep 17, 2020 via email

@fantapop
Copy link
Contributor Author

fantapop commented May 19, 2021

assuming #995 gets merged in, I think something here could be pretty straightforward. One idea is to check for a field on an error object which dictates the priority of whether it is the correct error. Tsoa users would then opt-in by having errors formatted with this additional field. Something like this could work:

const findHighestPriorityError = (failedAttempts) => {
    let highestPriError;
    for (const current of failedAttempts) {
         if (current.priority && (!highestPriError || highestPriError.priority < current.priority)) {
             highestPriError = current;
          }
     }
      return highestPriError;
 };

 try {
    request['user'] = await promiseAny(secMethodOrPromises);
    next();
} 
catch(err) {
    const error = findHighestPriorityError(failedAttempts) || failedAttempts.pop();
    error.status = error.status || 401;
    next(error);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants