0

I'm creating an application built with React, where API requests will be sent from http://localhost:3000 to a .NET server at https://localhost:5000. This works when windows authentication is disabled, but when windows authentication is enabled using IIS, any request, return 401 unauthorized.

I've done quite a bit of research and found that I can send a GET request fine by sending the axios request with { withCredentials: true }. If I send a POST request, this would still return 401 unauthorized from the server, unless I make the request a "simple-request", by setting the content type to application/x-www-form-urlencoded, according to these specifications: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS.

Is there something I need to have in the web config for these requests to work, when windows authentication is enabled?

An answer to a similar question here, does not help me: Angular 5: Post-request & windows authentication, since having both anonymous and windows authentication enabled, will result in the initial GET request to the server, not being able to get the Active Directory username, using windows authentication, since it seems like the Anonymous Authentication takes precedence.

I can make the POST request with the content type set to application/x-www-form-urlencoded, but this seems like the wrong way to go about it. Is there some way I can set some setting on the server, so that when windows authentication is enabled, the server at https://localhost:5000 will accept any API request from http://localhost:3000 with content type of JSON?

Allison Schambers
  • 221
  • 1
  • 3
  • 11

2 Answers2

1

You need to setup CORS on the server.

Here are some resources how to do it in Web API 2

Also according W3C spec CORS-preflight request never includes credentials so you might need to enable Anonymous for OPTIONS requests in IIS

UPDATE: Windows Auth vs OPTIONS requests

As I had struggled with the same issue recently, here is a small update.

Solution 1 (which I linked originally) - adding <allow verbs="OPTIONS" users="*"/> really does not work. Or better say it "sort of works" as it requires Anonymous authentication enabled in IIS which is something you don't want when using Windows Auth

Solution 2 actually really works. Key point is the code inside Application_AuthenticateRequest. Also important is that it works only when using integrated pipeline. It solves the problem of OPTIONS requests being stopped by Windows Auth (which happens if you have Anonymous authentication disabled no matter what you do)

Last solution mentioned by some MS employees here and here is to use IIS module (plugin) IIS CORS. Here is a configuration reference and short but useful introduction.

Obvious disadvantage of this is it needs to be installed on every server including your own dev machine. And apparently there is no easy way to install it into IIS Express. Luckily the "The Half-Blood Programmer" has created set of PowerShell scripts to automate this. Tested it and it works pretty well - just don't forget that Visual Studio creates a copy of the main applicationHost.config (usually located in the MyDocuments\IISExpress\config\ folder) in the solution folder .vs\%projectname%\config so you might need to run the script again for this copy....

Michal Levý
  • 14,671
  • 1
  • 27
  • 41
0

It turned out to be a CORS issue. The interesting thing I found was that enabling CORS in the following two ways do not work when windows authentication is enabled:

WebApiConfig.cs:

// Web API configuration and services
var cors = new EnableCorsAttribute("*", "*", "*") { SupportsCredentials = true };
config.EnableCors(cors);

Web.config:

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name = "Access-Control-Allow-Credentials" value="true" />
            <add name = "Access-Control-Allow-Headers" value="Origin, Accept, Content-Type, X-Auth-Token" />
            <add name = "Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
            <add name = "Access-Control-Max-Age" value="86400" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

This is the only way in which I would not get 401 unauthorized back from the API, was when I enabled CORS in the following way by putting it into the Global.asax.cs file, by returning 200 back for OPTIONS requests during the preflight check:

public void Application_BeginRequest(object sender, EventArgs e)
{
    string httpOrigin = Request.Params["HTTP_ORIGIN"];
    if (httpOrigin == null) httpOrigin = "*";
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", httpOrigin);
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Token");
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");

    if (Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.StatusCode = 200;
        var httpApplication = sender as HttpApplication;
        httpApplication.CompleteRequest();
    }
}
Allison Schambers
  • 221
  • 1
  • 3
  • 11