General:
Request URL:x/site.php
Request Method:OPTIONS
Status Code:302 Found
Remote Address:x.x.x.x:80
Response Headers:
view source
Access-Control-Allow-Headers:Content-Type
Access-Control-Allow-Origin:*
Access-Control-Max-Age:300
Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Length:0
Content-Type:text/html; charset=UTF-8
Date:Thu, 02 Mar 2017 14:27:21 GMT
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Location:y
Pragma:no-cache
Server:Apache/2.4.25 (Ubuntu)
Request Headers:
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
DNT:1
Host:x
Origin:http://127.0.0.1:3000
Pragma:no-cache
Referer:http://127.0.0.1:3000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.90 Safari/537.36
Apache virtualhost config looks as so:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "http://127.0.0.1:3000"
Header set Access-Control-Allow-Origin "http://127.0.0.1"
Header set Access-Control-Max-Age "300"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept"
Header set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, PATCH, OPTIONS"
</IfModule>
The preflight request is skipping the apache config and hitting my webapp directly, which does a redirect (hence the 302 and the location: y).
I don't know why the preflight request is not being handled by apache?
The two main things you need to change/add are:
- Use
Header always set
instead of just Header set
- Use mod_rewrite to handle the
OPTIONS
by just sending back a 200 OK
with those headers
So to enable the request in the question to work, here’s a minimal(ish) config snippet:
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Headers "Authorization"
Header always set Access-Control-Allow-Methods "GET, OPTIONS"
Header always set Access-Control-Expose-Headers "Content-Security-Policy, Location"
Header always set Access-Control-Max-Age "600"
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
Longer explanation at https://benjaminhorn.io/code/setting-cors-cross-origin-resource-sharing-on-apache-with-correct-response-headers-allowing-everything-through/
Some general notes on what values to set for the various Access-Control-
response headers:
Access-Control-Allow-Headers
: you must set it to include any header names your request sends except CORS-safelisted header names or so-called “forbidden” header names (names of headers set by the browser that you can’t set in your JavaScript); the spec alternatively allows the *
wildcard as its value—so you can try it someday, but no browser supports it yet: Chrome bug, Firefox bug, Safari bug
Access-Control-Allow-Methods
: the spec alternatively allows the *
wildcard—but again, as with Access-Control-Allow-Headers: *
, no browsers support it yet
Access-Control-Expose-Headers
: you must set to include any response headers your client code needs to read beyond Cache-Control
,Content-Language
,Content-Type
, Expires
, Last-Modified
and Pragma
—which are exposed by default (a lot of people forget to set this and end up baffled about why they can’t read the value of a particular response header); again the spec alternatively allows the *
wildcard here, but no browsers support it yet
Access-Control-Max-Age
: Chrome has an upper limit of 600
(10 minutes) hardcoded, so there’s no point in setting a higher value for it than that (Firefox may respect it, but Chrome will just throttle it down to 10 minutes if you set it higher, and Safari limits it to only 5 minutes)
So then, about the particular request shown in the question, here are some specific notes:
Your request has Access-Control-Request-Headers:authorization
so in your Apache config, add Authorization
in the Access-Control-Allow-Headers
response header too.
Origin
is a “forbidden” header name set by the browser, and Accept
is a CORS-safelisted header name, so you don’t need to include them in Access-Control-Allow-Headers
Your request sends no Content-Type
, so it isn’t needed in Access-Control-Allow-Headers
in the response (and never needed for GET
requests and otherwise only needed if the type is other than application/x-www-form-urlencoded
, text/plain
, or multipart/form-data
)
For Access-Control-Allow-Methods
, your request seems to just be a GET
, so unless you plan to also make POST
/PUT
/DELETE
/PATCH
requests, no point in explicitly including them