CORS preflight request fails due to a standard header
<p>While debugging a CORS issue I am experiencing I've found the following behaviour. Chrome makes the following OPTIONS preflight request (rewritten in CURL by Chrome itself):</p>

<pre><code>curl -v 'https://www.example.com/api/v1/users' -X OPTIONS -H 'Access-Control-Request-Method: POST' -H 'Origin: http://example.com' -H 'Accept-Encoding: gzip,deflate,sdch' -H 'Accept-Language: es-ES,es;q=0.8,en;q=0.6' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36' -H 'Accept: */*' -H 'Referer: http://example.com/users/new' -H 'Connection: keep-alive' -H 'Access-Control-Request-Headers: accept, x-api-key, content-type'
</code></pre>

<p>The response from the server to this request if the following:</p>

<pre><code>&lt; HTTP/1.1 403 Forbidden
&lt; Date: Thu, 21 Jul 2016 14:16:56 GMT
* Server Apache/2.4.7 (Ubuntu) is not blacklisted
&lt; Server: Apache/2.4.7 (Ubuntu)
&lt; X-Content-Type-Options: nosniff
&lt; X-XSS-Protection: 1; mode=block
&lt; Cache-Control: no-cache, no-store, max-age=0, must-revalidate
&lt; Pragma: no-cache
&lt; Expires: 0
&lt; Strict-Transport-Security: max-age=31536000 ; includeSubDomains
&lt; X-Frame-Options: SAMEORIGIN
&lt; Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
&lt; Content-Length: 20
&lt; Keep-Alive: timeout=5, max=100
&lt; Connection: Keep-Alive
</code></pre>

<p>being the body of the response 'Invalid CORS request'. If I repeat the request removing the header 'Access-Control-Request-Method' (and only that header) the OPTIONS requests succeeds with the following reponse:</p>

<pre><code>&lt; HTTP/1.1 200 OK
&lt; Date: Thu, 21 Jul 2016 14:21:27 GMT
* Server Apache/2.4.7 (Ubuntu) is not blacklisted
&lt; Server: Apache/2.4.7 (Ubuntu)
&lt; X-Content-Type-Options: nosniff
&lt; X-XSS-Protection: 1; mode=block
&lt; Cache-Control: no-cache, no-store, max-age=0, must-revalidate
&lt; Pragma: no-cache
&lt; Expires: 0
&lt; Strict-Transport-Security: max-age=31536000 ; includeSubDomains
&lt; X-Frame-Options: SAMEORIGIN 
&lt; Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with, x-api-key
&lt; Access-Control-Max-Age: 60
&lt; Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
&lt; Access-Control-Allow-Origin: *
&lt; Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
&lt; Content-Length: 0
&lt; Keep-Alive: timeout=5, max=100
&lt; Connection: Keep-Alive
</code></pre>

<p>However, the offending header is a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Request-Method" rel="noreferrer">CORS spec standard header</a> so it should not prevent the request from succeeding, right? Why is this header causing such behaviour?</p>

<p>And how can I tweak the access control headers sent by my server to make the request work when made with Chrome?</p>

<p>By the way, I am using Chrome 36.0, and the server is using Spring Boot, with the CORS headers being managed by Spring. </p>

<p>When the request is made by Firefox (v47.0) the behaviour is different but with an analogue result. Firefox does not even send the preflight request, it directly sends the POST request, which receives as response a 403 Forbidden. However, if I copy the request with the 'Copy as cURL' option, and repeat it from a terminal window, It succeeds and sends the correct CORS headers in the response. </p>

<p>Any idea?</p>

<p><strong>Update</strong>: Firefox does send the preflight OPTIONS request (as shown by the Live HTTP headers plugin), but Firebug masks it, so the behaviour in both browsers it exactly the same. In both browsers is the 'Access-control-request-method' header the difference that makes the request fail.</p>