ASP.NET MVC 4 WebAPI authorization

March 14, 2012

In the examples of ASP.NET MVC 4 WebAPI you can find that authorization is really easy.
You just have to add [Authorize] attribute to your controller or for some actions which need it.

And if you do this you will expect that your WebAPI will return error code 401 (Not authorized) to your client.

But unfortunately it's not happened.
And you can ask: what will happen in the real world?
I can answer: your browser just get the 302 (Found) status code and will redirect you to the login page.

I think it's not expected behavior for you. Because you want to get just 401 status code in the client.

And I can show you how you can achieve it.

Step 1

Please, double sure that you use AuthorizeAttribute from the System.Web.Http library instead of one from the System.Web.Mvc.

Step 2

Add a directory and two classes to your code which should "FIX" it.

Add App_Start directory to your solution.

We will create two classes in this directory in a minute.

Add first class into that folder.

This class is a HTTP module which do all the 'magic'.

The 'magic' is simple - just set the marker in PosrReleaseRequestState event if this is an ajax request and if our action returns status code equals to 401 (Unauthorized) or 403 (Forbidden). Then in OnEndRequest we have to check is this marker exists, and if yes, then set the returned status code from an action back.

    public class AjaxFormsAuthenticationModule : IHttpModule
    {

        private const string FixupKey = "__WEBAPI:Authentication-Fixup";

        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {
            context.PostReleaseRequestState += OnPostReleaseRequestState;
            context.EndRequest += OnEndRequest;
        }

        private void OnPostReleaseRequestState(object source, EventArgs args)
        {
            var context = (HttpApplication)source;
            var response = context.Response;
            var request = context.Request;

            bool isAjax = request.Headers["X-Requested-With"] == "XMLHttpRequest";

            if ((response.StatusCode == 401 || response.StatusCode == 403) && isAjax)
            {
                context.Context.Items[FixupKey] = response.StatusCode;
            }
        }

        private void OnEndRequest(object source, EventArgs args)
        {
            var context = (HttpApplication)source;
            var response = context.Response;

            if (context.Context.Items.Contains("__WEBAPI:Authentication-Fixup"))
            {
                response.StatusCode = (int)context.Context.Items[FixupKey];
                response.RedirectLocation = null;
            }
        }
    }

Add a second class into that folder.

This class will just register our HTTP module for our application.

using Microsoft.Web.Infrastructure.DynamicModuleHelper;

[assembly: PreApplicationStartMethod(typeof(FormsAuthenticationFixer), "Start")]

namespace LoginVS11.App_Start
{

    public static class FormsAuthenticationFixer
    {
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(AjaxFormsAuthenticationModule));
        }
    }
}

That's all.

After that all of your ajax requests will get the 401 status code if your client is not authorized yet.