ASP.NET Web API : Correct way to return a 401/unauthorised response

169,177

Solution 1

You should be throwing a HttpResponseException from your API method, not HttpException:

throw new HttpResponseException(HttpStatusCode.Unauthorized);

Or, if you want to supply a custom message:

var msg = new HttpResponseMessage(HttpStatusCode.Unauthorized) { ReasonPhrase = "Oops!!!" };
throw new HttpResponseException(msg);

Solution 2

Just return the following:

return Unauthorized();

Solution 3

As an alternative to the other answers, you can also use this code if you want to return an IActionResult within an ASP.NET controller.

ASP.NET

 return Content(HttpStatusCode.Unauthorized, "My error message");

Update: ASP.NET Core

Above code does not work in ASP.NET Core, you can use one of these instead:

 return StatusCode((int)System.Net.HttpStatusCode.Unauthorized, "My error message");
 return StatusCode(Microsoft.AspNetCore.Http.StatusCodes.Status401Unauthorized, "My error message");
 return StatusCode(401, "My error message");

Apparently the reason phrase is pretty optional (Can an HTTP response omit the Reason-Phrase?)

Solution 4

You get a 500 response code because you're throwing an exception (the HttpException) which indicates some kind of server error, this is the wrong approach.

Just set the response status code .e.g

Response.StatusCode = (int)HttpStatusCode.Unauthorized;

Solution 5

To add to an existing answer in ASP.NET Core >= 1.0 you can

return Unauthorized();

return Unauthorized(object value);

To pass info to the client you can do a call like this:

return Unauthorized(new { Ok = false, Code = Constants.INVALID_CREDENTIALS, ...});

On the client besides the 401 response you will have the passed data too. For example on most clients you can await response.json() to get it.

Share:
169,177
GoatInTheMachine
Author by

GoatInTheMachine

Updated on July 08, 2022

Comments

  • GoatInTheMachine
    GoatInTheMachine almost 2 years

    I have an MVC webapi site that uses OAuth/token authentication to authenticate requests. All the relevant controllers have the right attributes, and authentication is working ok.

    The problem is that not all of the request can be authorised in the scope of an attribute - some authorisation checks have to be performed in code that is called by controller methods - what is the correct way to return a 401 unauthorised response in this case?

    I have tried throw new HttpException(401, "Unauthorized access");, but when I do this the response status code is 500 and I get also get a stack trace. Even in our logging DelegatingHandler we can see that the response is 500, not 401.

  • GoatInTheMachine
    GoatInTheMachine almost 9 years
    It's a bit odd then that the exception takes the HTTP status code as a parameter, and intellisense docs say that this is the status code sent to the client - I was hoping to avoid mutating the response myself directly as this seems error prone, seeing as its global state
  • LukeH
    LukeH almost 9 years
    The base Web API controller doesn't expose a Response property.
  • JohnWrensby
    JohnWrensby over 7 years
    I think the accepted answers the OP's question specifically. My answer answers the question's title "ASP.NET Web API : Correct way to return a 401/unauthorised response"
  • aruno
    aruno almost 6 years
    Anybody know why there's no overloaded version of this with a message?
  • Dai
    Dai over 5 years
    This no-longer works in ASP.NET Core, the ControllerBase class (used by ASP.NET Core WebAPI) no-longer has a Content overload that accepts a HTTP status code.
  • Rikki
    Rikki over 5 years
    @Simon_Weaver No idea why, but you could use a return Content<string>(HttpStatusCode.Unauthorized, "Message"); to do this.
  • Nick Turner
    Nick Turner over 5 years
    This should be the correct answer. 1 it is correct. 2) If this changes in a later framework, you don't have to change code. 3) You don't need to provide a reason to a 401. This should be handled by the client and not the server.
  • Nick Turner
    Nick Turner over 5 years
    This is wrong. A Content response is a 200 Ok status. The server should send a 401 and the client should handle accordingly. You can't send a 200 as a 401. It doesn't make sense. If the client gets a 401, it's not an Oops, it's a your breaking the law.
  • Alex AIT
    Alex AIT over 5 years
    This code is sending a 401 status code(HttpStatusCode.Unauthorized), not 200. Content(...) simply a shorthand for returning any given content with a given HTTP status code. If you want to send 200 you can use Ok(...)
  • Chris F Carroll
    Chris F Carroll about 5 years
    @NickTurner -- that's an argument for the webapi2 Content() method being poorly named not for this being the wrong answer. Since the (status,message) method is renamed in NetCore, I guess the devs agree it was poorly named.
  • Nae
    Nae almost 5 years
    Which library is this in?
  • Jon Story
    Jon Story about 4 years
    @Rikki it can be nice to pass some kind of "loggable" message along with the response. That way you can inform the client of the reason they could not authenticate: eg "API key revoked", or "Key does not exist" etc. They can still choose whether to log the message or just ignore it and handle the status code, but at least then you don't leave the developer on the other end wondering why their code won't work
  • Jon Story
    Jon Story about 4 years
    You do not need to set the StatusCode again if you pass it to the constructor - using either is fine
  • Niels Lucas
    Niels Lucas almost 4 years
    The question is about an web API. So this would be an invalid answer if am not wrong? API should not return 'actions', only results.
  • Mars
    Mars over 3 years
    403 is Forbidden, not 401 Unauthorized. There's a great explanation about the difference here
  • Jack Miller
    Jack Miller about 3 years
    HttpResponseException is part of NuGet package Microsoft.AspNetCore.Mvc.WebApiCompatShim which provides compatibility in ASP.NET Core MVC with ASP.NET Web API 2. That is, it allows you to go the non-Core way in Core projects. So for Core projects, this is not the "Correct way".
  • Eric Brown - Cal
    Eric Brown - Cal over 2 years
    Wasnt' HttpResposeException removed from .netcore? stackoverflow.com/questions/47142142/…
  • pantonis
    pantonis about 2 years
    Totally wrong. as @Mars said 403 is Forbidden whereas 401 is for Unauthorized requests