Setting CORS (cross-origin resource sharing) on Apache with correct response headers allowing everything through

July 30, 2014

Once in a while you need to make a cross-domain request from Javascript, this is something the browser very much dislikes. I’m no expert on CORS, and I feel that all the documentation on it is pretty bad. But I thought, “Anybody can google”, and so I did.

I started off with just adding the Access-Control-Allow-Origin header in my Apache configuration, thinking that it’ll solve my problems. I also decided to set it on wildcard, allowing anything to request resources.

# In my virtualhost config
Header set Access-Control-Allow-Origin "*"

Restart server, reload page, and I was greeted with the normal cross-domain error.

# Chrome developer tools
OPTIONS http://my.example.dev/setting/1316 405 (Method Not Allowed) 

# Firefox developer tools
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://my.example.dev/setting/1316. This can be fixed by moving the resource to the same domain or enabling CORS.

I kept adding config flags until it looked something like this

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header set Access-Control-Max-Age "1000"
Header set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"

I still got the same error. At this point I started to look more into the error, “OPTIONS http://my.example.dev/setting/1316 405 (Method Not Allowed)” or “OPTIONS Method Not Allowed”, I looked under the network tab and noticed that the request method was “OPTIONS”, so I started digging and as if I understood correctly, this is a “pre-flight” request, basically asking the server for the CORS headers, but without data.

The API I was communicating with was not configured to handle OPTIONS request, nor was it supposed to. I decided I didn’t want to hack on the API code instead I wanted to try and circumvent this through Apache.

I added a small rewrite to the virtualhost configuration, basically responding with a 200 SUCCESS on every OPTIONS request.

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header set Access-Control-Max-Age "1000"
Header set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"

# Added a rewrite to respond with a 200 SUCCESS on every OPTIONS request
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

Progress! It still didn’t work, but I got a new error;

# Chrome developer tools
XMLHttpRequest cannot load http://my.example.dev/setting/1316. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://mydevsite.dev' is therefore not allowed access. 

# Firefox developer tools
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://my.example.dev/setting/1316. This can be fixed by moving the resource to the same domain or enabling CORS.

So by looking at the errors, it looks like the “Access-Control-Allow-Origin” response header is missing, but I’ve already added it to my config with a wildcard domain.
The problem occurs because I don’t cleanly respond with the RewriteRule, I actually redirect the request to a 200 SUCCESS which means earlier response flags were removed. All I had to do was set the “Always” flag on my “Header set” rule.

So for my final try, which was successful, my configuration looked like this;

# Always set these headers.
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"

# Added a rewrite to respond with a 200 SUCCESS on every OPTIONS request.
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

And voilà, everything is playing nicely. Hopefully this can help another unfortunate soul trying to navigate through the pitfalls of CORS.

Please note that I haven’t used this config on a production server, just on local development servers, allowing wildcard domains for CORS will create security issues on your site!

Tags