snippets > troubleshoot-cors-issues-api-requests

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 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 OPTIONS
  • three headers must be present: Access-Control-Request-Method, Access-Control-Request-Headers and Origin. Be wary, however, that the domain stated on Origin must 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-Methods, Access-Control-Max-Age and 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.

Further reading

Light overview of preflight requests

Official specification of the Fetch standard for preflight requests