0

I have two Projects, one is MVC (using Angular) and other is WebAPI. Windows Authentication is working fine in MVC (thanks to this article)

However, when I am making AJAX calls from MVC site through Angular to WebAPI then I get following error:

HTTP Error 401.2 - Unauthorized You are not authorized to view this page due to invalid authentication headers.

Most likely causes:

  • No authentication protocol (including anonymous)is selected in IIS.
  • Only integrated authentication is enabled, and a client browser was used that does not support integrated authentication.
  • Integrated authentication is enabled and the request was sent through a proxy that changed the authentication headers before they reach the Web server.
  • The Web server is not configured for anonymous access and a required authorization header was not received.
  • The "configuration/system.webServer/authorization" configuration section may be explicitly denying the user access.

I read this post but it is talking about HttpClient (while I am using JQuery or Angular) to make calls.

PLEASE NOTE: If I hit the WebAPI URL through Browser then Authentication works fine. So it must be something to do with AJAX request.

This is my code in Global.asax

protected void Application_BeginRequest()
{
    if (ValidateRequest())
    {
        //var origin = Request.Headers["Origin"];
        Response.Headers.Remove("Access-Control-Allow-Origin");

        Response.AddHeader("Access-Control-Allow-Origin", matchedOrigin);

        Response.Headers.Remove("Access-Control-Allow-Headers");
        Response.AddHeader("Access-Control-Allow-Headers", CustomConfig.HEADERS);

        Response.Headers.Remove("Access-Control-Allow-Methods");
        Response.AddHeader("Access-Control-Allow-Methods", CustomConfig.METHODS);
    }

    // This is to avoid "Method 405 Not allowed" error
    if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
    {
        Response.Flush();
        Response.End(); //Send the Empty Response for Options (Preflight Request)
    }
}

I have done enough research but couldn't find a solution. So couple of things.

  • How can I resolve my above issue
  • Secondly what's the best approach for using Windows Authentication based on my scenario (And Project setup).
Community
  • 1
  • 1
programmerboy
  • 341
  • 5
  • 15

1 Answers1

0

If it works in the browser directly but not when JavaScript is involved it will be a CORS issue so check you have it all enabled, including handling pre-flight OPTIONS verb.

In your case you will also need to check you are passing credentials e.g.

[EnableCors(origins: "http://myclient.azurewebsites.net", headers: "*", 
    methods: "*", SupportsCredentials = true)]

Note with credentials I don't think you can have a wildcard origin - needs explicit list.

See this link: https://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#credentials.

In your Angular $http request make sure you have the property withCredentials: true.

Or if you are making a JQuery ajax call then:

xhrFields: {
        withCredentials: true
    }

If you still have pre-flight problems try a custom message handler like this (change the origin(s)):

    public class ExampleMessageHandler : DelegatingHandler
    {
      protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
            CancellationToken cancellationToken)
        {

            if (request.Headers.Contains("Origin") && request.Method.Method == "OPTIONS")
            {
                var response = new HttpResponseMessage();
                response.StatusCode = HttpStatusCode.OK;
                response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:8080/");
                response.Headers.Add("Access-Control-Allow-Credentials", "true");
                response.Headers.Add("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization");
                response.Headers.Add("Access-Control-Allow-Methods", "DELETE, POST, PUT, OPTIONS, GET");
            }
            return base.SendAsync(request, cancellationToken);
        }
   }

Then:

public static void Register(HttpConfiguration config)
    {
        config.MessageHandlers.Add(new ExampleMessageHandler());
Ben Hall
  • 1,353
  • 10
  • 19
  • I doubt it is a CORS issue since it was working perfectly before I enabled Windows Authentication on WebAPI Project. I believe it has to do something with credentials but don't know what. – programmerboy Oct 31 '16 at 23:16
  • Thanks Ben. Your suggestion worked but not completely. Now for Pre-flight (OPTIONS) request I get 401 unauthorized as per my research browsers don't send credentials for Options request. And I guess WebAPI is looking for credentials. I was able to get around by following this post [link]http://stackoverflow.com/a/28439989/1813357 but not sure if this is a good solution. – programmerboy Nov 01 '16 at 15:02
  • Message handler is executed for GET requests but it doesn't get hit for OPTIONS request. I was handling the OPTIONS verb in `Global.asax` `Application_BeginRequest` just like it is done in the example post. – programmerboy Nov 01 '16 at 16:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/127115/discussion-between-programmerboy-and-ben-hall). – programmerboy Nov 01 '16 at 16:52