How to make ASP.NET Web API respond 403 or 401 appropriately?
asp.net-web-api, authentication, authorization, http, rest
Solution
Reading Parv's suggestion, I created the following custom filter called [WebApiAuthorize].
The key is the HandleUnauthorizedRequest() method. When code is executing inside this method, it is because the user is unauthorized "for some reason".... so now we just determine out "why".... and then either:
- Call base method for default behavior (return 401).... or....
- Return our own response with a 403.
As you can see, it returns 403 when appropriate (authenticated, but not authorized).
public class WebApiAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(HttpActionContext ctx)
{
if (!ctx.RequestContext.Principal.Identity.IsAuthenticated)
base.HandleUnauthorizedRequest(ctx);
else
{
// Authenticated, but not AUTHORIZED. Return 403 instead!
ctx.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
}
}
To use, just throw the custom filter on a controller or action like this.....
[WebApiAuthorize(Roles = "YourRoleA,YourRoleB")]
public class AdminController : ApiController
{
public List<Admin> GetAdmins()
{
...
}
}
Problem
I am using ASP.NET Web API. And I do like the ability to add attributes to specify levels of access to the API controllers like this: ``` [Authorize] public IEnumerable<Activity> Get() ``` So far so good, but when I use roles the concept breaks apart. ``` [Authorize(Roles = "Manager")] public IEnumerable<Activity> Get() ``` My user may have logged on to the system a while back, and then at some point they hit a resource that is "forbidden" to them. There is no sense in the user attempting to log on again. Since their rightful account does not have access to that URL. But currently they get a 401 (unauthorized) instead of a 403 (forbidden) as if they had logged on with the wrong account. But the user only has one account, and it is not intended that users ask for an account that belongs to someone else. Has anyone else dealt with this problem? Does anyone know how to fix this? I am more than willing to write the code to fix this, but I am currently at a loss on where to start.