All About CORS Headers
There are already a lot of resources about CORS out there.
I’m going to try and keep this short and sweet — useful tips for web devs.
About CORS
- CORS is a security mechanism based on HTTP headers.
- CORS must be configured on the web server and consumed by the browser.
- It is only relevant for web browsers, not requests from other software such as cURL or a Python script (which will ignore the configuration).
Why Does It Exist?
- You are on a website with
mydomain.com. - All web browsers have a Same-Origin-Policy (SOP), preventing access to domains
such as
sub.mydomain.comorotherdomain.com, as a security measure. - Cross-Origin Resource Sharing (CORS) is a mechanism to allow exceptions to this rule.
When Is It Triggered?
- If the schema, hostname, or port do not match, this is considered cross-origin.
- An example would be
https://mysite.comandhttps://api.mysite.com, which are different domains and hence cross-origin. - To avoid CORS for backend APIs, a common approach is to host the API under
a subpath instead
https://mysite.com/api, and avoid CORS concerns entirely.
Configuring CORS Correctly
Pre-Flight Requests
-
Browsers send a “pre-flight” request under certain conditions before making the actual request (for cross-origin requests).
-
A pre-flight request is a special
OPTIONSrequest that checks the browser is allowed to submit to the API before making the actual request.Tip
The most common triggers for this are:
- Using HTTP methods other than
GET,HEAD, orPOST. - Using headers other than simple headers (
Accept,Accept-Language,Content-Language,Content-Typewith specific values). - Using
Content-Typewith values other thanapplication/x-www-form-urlencoded,multipart/form-data, ortext/plain. - Including credentials (
credentials: include).
- Using HTTP methods other than
-
As above, to avoid CORS and having to send two requests per API call, it’s possible to host an API under a subpath instead.
Tip
If you are using a firewall or proxy, ensure that the
OPTIONSmethod is present in Access-Control-Allow-Methods (see further details below).
Access-Control Headers
- These headers control how CORS is enforced by the browser.
- They are set on the web server of the resource you are trying to access, e.g. your NGINX proxy or backend API.
Access-Control-Allow-Origins
- Which origins in the browser can call the API / webserver endpoints.
- Examples:
Access-Control-Allow-Origin: *(allow all access)Access-Control-Allow-Origin: https://example.com(specific protocol (https), domain (example.com), and port (443)))
Access-Control-Allow-Credentials
-
If cookies or HTTP basic auth should be sent with cross-origin requests.
-
Example:
Access-Control-Allow-Credentials: true(allow).Warning
Cannot be set to
trueifAccess-Control-Allow-Origin: *.
Access-Control-Allow-Methods
- Specifies which HTTP methods are permitted for cross-origin requests.
- Example:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE.
Access-Control-Expose-Headers
- Specifies which headers the browser can access from the response.
- Example:
Access-Control-Expose-Headers: Content-Length,Content-Range. - A good example for this is the Content-Disposition which may contain the
original filename of an attachment sent by the server:
- For the filename:
Content-Disposition: attachment; filename="myphoto.jpg" - Allow the header to be read:
Access-Control-Expose-Headers: Content-Disposition. - The browser can now download the file with the original filename.
- For the filename:
Other headers
- Cross-Origin-Resource-Policy (CORP): controls how strict the CORS policy is:
same-origin: Only allow requests from the exact same origin.same-site: Allow requests from subdomains (e.g. api.example.com for example.com).cross-origin: Allow all requests from any domain.
- Cross-Origin-Opener-Policy (COOP) & Cross-Origin-Embedder-Policy (COEP): typically used for security and performance optimizations. A common example is usage with the Origin Private File System (OPFS) and SharedArrayBuffer.
- Access-Control-Max-Age: defines how long the results of a pre-flight request can be cached before needing to run again.