Cross Origin Resource Sharing (a.k.a. CORS) is a powerful, and yet misunderstood, web standard for protecting web APIs from abuse. If you’re anything like me, however, you had your fair share of wasted work hours trying to deal with it from time to time. The concept seems deceptively simple, but the devil is in the details.
First of all, its important to understand that CORS compliance is an optional standard and is mostly enforced by browsers, like Chrome, Firefox and Safari. Therefore, it’s unlikely that you will face issues with it while working with libraries like Python’s Requests or CLI tools like curl.
However, if you have a frontend application running on your browser with a domain like, let’s say,
http://localhost:3000, API calls directed to different domains, like
https://laury.dev, will be preceded by a preflight request. This determines if the browser will execute the main request or not.
When having problems with this process, you may see an error similar to this on your Chrome console:
Access to XMLHttpRequest at ‘https://laury.dev from origin ‘http://localhost:3000 has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
To reproduce the problem in a more isolated manner, you can use
curl to make a preflight request manually. The important parts here are:
- the HTTP method has to be
- three headers must be present:
Origin. Be wary, however, that the domain stated on
Originmust mention protocol, FQDN, port (if any is being used), and no trailing slash.
Here’s an example:
curl -IX OPTIONS https://google.com \ -H "Access-Control-Request-Method: POST" \ -H "Access-Control-Request-Headers: origin, x-requested-with" \ -H "Origin: http://mywebsite.com:3000"
For a preflight request to be considered successful, all of the following must be true:
- the HTTP status on the response is within 200-299
- the response contains these headers:
Access-Control-Allow-Origin. One extra catch here is that this last header cannot present the value
*when the main request contains authentication information (like cookies). If it does, the preflight will be considered a failure by the browser. In this case, the header has to mention the origin domain explicitly.
Kubernetes users running Ingress Nginx
To manage CORS headers on Ingress Nginx, you may use these annotations on Ingress objects. Even objects that only manage paths inside domains will work with them, so there’s no need to enable CORS on the entire domain if you don’t feel like it.