October 12, 2022
Troubleshoot CORS-related issues on API requests
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 have 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, it’s important to understand that CORS compliance is optional 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 you run into problems with this process, you may see an error similar to this in your browser 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
OPTIONS - three headers must be present:
Access-Control-Request-Method,Access-Control-Request-HeadersandOrigin. Be aware, however, that the domain stated inOriginmust include the 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-Methods,Access-Control-Max-AgeandAccess-Control-Allow-Origin. One extra catch: this last header cannot use 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.
Further reading
Light overview of preflight requests
Official specification of the Fetch standard for preflight requests