Asp.Net Web Api:Correct Way to Return a 401/Unauthorised Response

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

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);

How to return status code 401 along some additional data?

Answering your first question, this is how overridden method of authorization attribute may look like. Error message will be status message and content is in response body.

public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
string errorMessage = "User has no enough permissions to perform requested operation.";

var httpContent = new StringContent("{ \"some\": \"json\"}", Encoding.UTF8, "application/json");

actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden)
{
ReasonPhrase = errorMessage,
Content = httpContent
};

return Task.FromResult<object>(null);
}

From MVC action you can return status code like this return StatusCode(418); or using dedicated method like return Unauthorized();. To redirect you can use RedirectToAction or context.Response.Redirect

How to return Unathorized from .Net Core Web API

If the only reason you don't have a IActionResult return type is because you want to return json data, you can still return it and do this:

public IActionResult GetSomeData()
{
if (condition)
return Json(myData);
else
return Unauthorized();
}

A little hacky, but you can also simply return null and configure your response using HttpContext

public SomeData GetSomeData()
{
if (condition) return myData;
else
{
HttpContext.Response.StatusCode = 401;
return null;
}

}

If you need SomeData for some reason such as type safety, one of your options are to set up a filter class.

public class MyAccessAttribute : Attribute, IActionFilter{

public void OnActionExecuting(ActionExecutingContext context)
{
if (condition)
context.Result = new UnauthorizedResult();
}

public void OnActionExecuted(ActionExecutedContext context)
{
}
}

You can then use it on your action like this:

[MyAccess]
public SomeData GetSomeData(){

Update
As of .netcore 2.1 you can now use generic ActionResult

 public ActionResult<SomeData> GetSomeData(){

Unauthorised webapi call returning login page rather than 401

There are two AuthorizeAttribute implementations and you need to make sure you are referencing the correct one for Web API's. There is System.Web.Http.AuthorizeAttribute which is used for Web API's, and System.Web.Mvc.AuthorizeAttribute which is used for controllers with views. Http.AuthorizeAttribute will return a 401 error if authorization fails and Mvc.AuthorizeAttribute will redirect to the login page.

Updated 11/26/2013

So it appears things have drastically changed with MVC 5 as Brock Allen pointed out in his article. I guess the OWIN pipeline takes over and introduces some new behavior. Now when the user is not authorized a status of 200 is returned with the following information in the HTTP header.

X-Responded-JSON: {"status":401,"headers":{"location":"http:\/\/localhost:59540\/Account\/Login?ReturnUrl=%2Fapi%2FTestBasic"}}

You could change your logic on the client side to check this information in the header to determine how to handle this, instead of looking for a 401 status on the error branch.

I tried to override this behavior in a custom AuthorizeAttribute by setting the status in the response in the OnAuthorization and HandleUnauthorizedRequest methods.

actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

But this did not work. The new pipeline must grab this response later and modify it to the same response I was getting before. Throwing an HttpException did not work either as it is just changed into a 500 error status.

I tested Brock Allen's solution and it did work when I was using a jQuery ajax call. If it is not working for you my guess is that it is because you are using angular. Run your test with Fiddler and see if the following is in your header.

X-Requested-With: XMLHttpRequest

If it is not then that is the problem. I am not familiar with angular but if it lets you insert your own header values then add this to your ajax requests and it will probably start working.

asp mvc web api return 401 unauthorized

use [AllowAnonymous] attribute on intended controller for all actions on that cotroller

[AllowAnonymous] // Applies to all ations
public class MyController : ApiController {
public IHttpActionResult MyAction1() {
//...
}

public IHttpActionResult MyAction2() {
//...
}
}

or only on the intended action

public class MyController : ApiController {
[AllowAnonymous] // Applies to only this ation
public IHttpActionResult MyAction() {
//...
}

//Still secure
public IHttpActionResult MyAction2() {
//...
}
}

When done testing you can remove them.



Related Topics



Leave a reply



Submit