Chrome v37/38 CORS failing (again) with 401 for OPTIONS pre-flight requests Chrome v37/38 CORS failing (again) with 401 for OPTIONS pre-flight requests google-chrome google-chrome

Chrome v37/38 CORS failing (again) with 401 for OPTIONS pre-flight requests


@Cornel Masson, did you solve the problem? I do not understand why your server is asking you to authenticate the OPTIONS request, but I am facing this same issue against a SAP NetWeaver server. I have read the whole CORS specification (I recommend) so I can clarify you some of your doubts.

About your sentence

In the Angular app I explicitly set the following request headers. AFAIK this setting for withCredentials should ensure that credentials are sent even for OPTIONS requests:

  • According to the CORS specification when a user agent (thus, a browser) preflights a request (requests with OPTIONS HTTP method), it MUST exclude the user credentials (cookies, HTTP authentication...) so any OPTIONS request cannot be requested as authenticated. The browser will request as authenticated the actual request (the one with the requested HTTP method like GET, POST...), but not the preflight request.
  • So browsers MUST not send the credentials in OPTIONS request. They will do in actual requests. If you write withCredentials = true the browser should do what I say.

According to your sentence:

It looks like Chrome is pre-flighting all my POSTs due to the content-type: "application/json":

  • The specification also says that a preflight request will be made by the browser when the header is not a "simple header" and here you have what that means:

    A header is said to be a simple header if the header field name is an ASCII case-insensitive match for Accept, Accept-Language, or Content-Language or if it is an ASCII case-insensitive match for Content-Type and the header field value media type (excluding parameters) is an ASCII case-insensitive match for application/x-www-form-urlencoded, multipart/form-data, or text/plain.

  • application/json is not included so the browser MUST preflight the request as it does.
If anyone finds a solution it would be appreciated.

EDIT: I just found a person with same problem that reflects the real problems, and if you uses the same server as him you will be lucky, https://evolpin.wordpress.com/2012/10/12/the-cors/


Same here. I use Windows NTLM Authentication. Up until Chrome version 37 it worked OK. On versions 37, 38 it fails with 401 (Unauthorized) due to request Authorization header missing in pre-flight OPTIONS on both PUT, and POST.

Server side is Microsoft Web Api 2.1. I tried various CORS including latest NuGet package from Microsoft to no avail.

I have to workaround on Chrome by sending GET request instead of POST, and breaking rather huge data in multiple requests, since URL has a limit in size naturally.

Here are Request/Response headers:


Request URL: http://localhost:8082/api/ConfigurationManagerFeed/Method: OPTIONSStatus: 401 UnauthorizedRequest HeadersAccept: */*Accept-Encoding: gzip,deflate,sdchAccept-Language: en-US,en;q=0.8,ru;q=0.6Access-Control-Request-Headers: accept, content-typeAccess-Control-Request-Method: POSTConnection: keep-aliveHost: localhost:8082Origin: http://localhost:8383Referer: http://localhost:8383/Application/index.htmlUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36X-DevTools-Emulate-Network-Conditions-Client-Id: 49E7FC68-A65C-4318-9292-852946051F27Response HeadersCache-Control: privateContent-Length: 6388Content-Type: text/html; charset=utf-8Date: Fri, 24 Oct 2014 13:40:07 GMTServer: Microsoft-IIS/7.5WWW-Authenticate: NegotiateNTLMX-Powered-By: ASP.NET


On MS IIS I implemented another workaround by overriding Microsoft standard page life cycle, i.e. processing OPTIONS right at the beginning of the HTTP request in global.ascx:

public class Global : HttpApplication{    /// <summary>Check and cofigure CORS Pre-flight request on Begin Request lifecycle    /// </summary>    protected void Application_BeginRequest()    {        if (Request.Headers.AllKeys.Contains(CorsHandler.Origin) && Request.HttpMethod == "OPTIONS")        {            Response.StatusCode = (int)HttpStatusCode.OK;            Response.Headers.Add(CorsHandler.AccessControlAllowCredentials, "true");            Response.Headers.Add(CorsHandler.AccessControlAllowOrigin, Request.Headers.GetValues(CorsHandler.Origin).First());            string accessControlRequestMethod = Request.Headers.GetValues(CorsHandler.AccessControlRequestMethod).FirstOrDefault();            if (accessControlRequestMethod != null)            {                Response.Headers.Add(CorsHandler.AccessControlAllowMethods, accessControlRequestMethod);            }            var hdrs = Request.Headers.GetValues(CorsHandler.AccessControlRequestHeaders).ToList();            hdrs.Add("X-Auth-Token");            string requestedHeaders = string.Join(", ", hdrs.ToArray());            Response.Headers.Add(CorsHandler.AccessControlAllowHeaders, requestedHeaders);            Response.Headers.Add("Access-Control-Expose-Headers", "X-Auth-Token");            Response.Flush();        }    }}