CORS stands for Cross-Origin-Resource-Sharing and is the HTTP mechanism to allow servers to accept requests from other host locations other than its own.
Getting CORS up and running is not difficult. There are plenty of posts online that will recommend a starting configuration that looks something like this, in pseudo code
Header().Set("Access-Control-Allow-Origin", "*")
Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Authorization")
This configuration works great and is the default I use; however, it does not work if you need to receive and set cookies in the browser. This short blog post documents what I learnt about working with cookies with CORS.
When I needed to set cookies in a server accessed behind CORS, I didn’t think anything special was needed as the CORS requests were completing without errors.
Cookies was not getting set however. It turned that browsers (tested on Chrome and Firefox) SILENTLY ignore cookie headers if CORS is not configured correctly.
Due to the lack of errors from browsers, it was not clear to me at first why cookie headers were not
taking effect as I could see from curl
that the backend was definitely replying with the correct
cookie headers.
Stumped, I did what every good engineer do at this point, I Googled “set cookie header not setting cookie” and very quickly CORS came up as a possible culprit.
Turns out, in order for cookie headers to work across origin, the CORS header Access-Control-Allow-Origin
must not specify *
and instead needs to specify the requesting origin.
To put it concretely, for cookie header to be accepted by a browser, your server need to write, again in pseudo code
Header().Set("Access-Control-Allow-Origin", IncomingRequest.Host)
After this configuration change, setting cookie via CORS worked.
Now that we can set cookies, receiving cookies on the server should just work automatically, right?
Almost. Fixing the CORS header Access-Control-Allow-Origin
is a pre-requisite to setting and receiving
cookies but turned out two more configuration updates are required.
First, from your web app, you need to make sure your AJAX request specifies withCredentials
equal to true
to make a request with cookies, which by default is not forwarded (presumably for security reasons).
Second, backend server needs to reply with Access-Control-Allow-Credentials: true
or else the response
will be dropped.
Interacting with cookie with CORS now works as expected, after many trials and errors, all of which could have been avoided had I read Mozill’s excellent MDN docs https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS first. Oh well