2

In my .NET Core Web API, I have a method that gets called after they AD/Okta login to the app. Then certain data based tests fail about a user (stuff not stored in ad or okta, like this user is not a student), I'm throwing an AuthorizationException, to indicate this person is not allowed to log in.

The client gets a 500 error, is there a good way to make it return a 401 unauthorized instead?

I'm using a global exception filter, for another use, this seems like a good place to do it.

public void OnActionExecuted(ActionExecutedContext context)
{
    if (context.Exception is ApiErrorException ex)
    {
        var bdo = new BaseReturnDataObject(ex.Message, ex.Type);

        context.Result = new JsonResult( bdo ) { };
        context.ExceptionHandled = true;
    }
    // do it about here 
}

Except that I only have access to the response, not the request on the context object.

My issue is the client is going to treat a 500 from calling the specific API method as a "you are not authorized" and there is no way to differentiate it from a "your service is broken" , as it's the first method called on each login.

I kind of half way remember reading a post on SO about someone doing this because it offended them that the return type was 500 and not 401, and it being a bad idea, but I can't find it when I search for it. Is there a good reason not to change the error type?

If I don't change the return type is there a good way to embed the exception.message into the 500 result sent to the client so I can differentiate between the reasons for the 500?

I guess what I'm asking for is what is the best practice to tell the 2 types of error apart at the client end? Returning a 401 seems on the face like the right answer.

Edit: I guess what I'm asking here is what is the best practice and why is it the best practice in this situation?

Eric Brown - Cal
  • 14,135
  • 12
  • 58
  • 97
  • 3
    There’s some unhandled exception in your code, you need to debug – Vivek Nuna Oct 15 '21 at 18:32
  • 1
    Yes there is, I'm throwing a AuthorizationException, how do I handle it and return a 401 instead of a 500? – Eric Brown - Cal Oct 15 '21 at 18:41
  • 2
    Don't throw the AuthorizationException, cause the flow of your code to return a result that represents the Unauthorised response, not an exception – phuzi Oct 15 '21 at 18:43
  • So return a 200 with a special message in the body? – Eric Brown - Cal Oct 15 '21 at 19:00
  • 1
    With 200, you're saying everything is OK and the client needs to parse the body. Instead, set the status code to [4xx](https://stackoverflow.com/questions/3297048/403-forbidden-vs-401-unauthorized-http-responses) with `context.HttpContext.Response.StatusCode = 401`. – Jasen Oct 15 '21 at 20:43
  • In MVC, you use the `app.UseAuthorization()` middleware to check if the user satisfies the required authorisation policy for each request. – Jeremy Lakeman Nov 07 '21 at 23:52

1 Answers1

1

You're reinventing the wheel with your approach. This is already taken care of by the framework. Use the standard Net Core authorization process as detailed in their documentation. TLDR, dont throw custom exceptions for authentication/authorization

https://learn.microsoft.com/en-us/aspnet/core/security/authorization/simple?view=aspnetcore-6.0

Robert Perry
  • 1,906
  • 1
  • 14
  • 14