All You Need To Know About CORS
I’ll never forget the first time I stumbled across a Cross-Origin Resource Sharing (CORS) error. Trying to digest terms like the Same-origin policy, preflight requests, CORS policy, and Access-Control-Allow-Origin header all at once left me with more questions than answers.
Today, let’s dive into the world of CORS and why it’s the bane of developer’s existence. I promise it’ll only take 5 minutes to get a good grasp on it!
If you're just looking to resolve your CORS errors, skip right ahead to the solution!
What the heck is CORS?
So, what is CORS, and why does it keep insisting on ruining our day?!
Imagine this: you’re working on a fancy new website, let’s call it example.com
. You’ve built a sleek frontend, and you’re ready to hook it up with your backend API from api.example.com
.
You’ve tested the API a million times on Postman, and everything looks perfect. The response structure is flawless, and you’re feeling super confident. But then, you send a request from your webpage to the API, and bam — you're hit with the dreaded CORS error:
Basically, CORS is a security mechanism that browsers enforce to prevent websites from making requests to domains different from the one serving the web page. Think of it like having a bouncer at a club who only lets in people from the same neighborhood (or domain, in this case).
example.com
and api.example.com
the same domain?Not quite! Even though they share the same domain name, they are considered different origins because they have different subdomains. In the world of CORS, the scheme/protocol, domain, and port must match exactly for two URLs to be considered the same origin.
See this determination rules table for the Same-origin policy.
When do CORS errors happen?
Here's the kicker: CORS errors only happen when you're making requests to APIs hosted on different domains from the browser.
If you're testing your API with Postman or Insomnia (or any other API development/testing tool), you'll never see this error because those tools don't give a damn about CORS rules.
Okay, what’s going on? Why is my browser doing this?
Well, your browser is just trying to protect you from potential vulnerabilities (e.g. CSRF attacks).
How? When your website makes a request to an API on a different domain, the browser sometimes automatically performs a series of steps to ensure the request is safe.
This process involves making a preflight request (which is an OPTIONS request) sent by the browser to the API server before the actual request is made.
Preflight Requests
Here's an example of preflight requests in the network tab:
The preflight request (automatically issued by the browser) checks if the server allows the cross-origin request and includes the necessary CORS headers.
If the server responds with the appropriate CORS headers, the browser proceeds with the actual request. Otherwise, the request is blocked.
Wait, you said sometimes?
Preflight requests are only triggered for certain cross-origin requests.
Yep, you heard that right. The browser will only send a preflight request if the actual request meets any of the following conditions:
- Only for certain types of requests, e.g. POST, PUT, DELETE
- Your request includes custom headers (e.g.,
X-Custom-Header
) - The
Content-Type
header has a value other thanapplication/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
. Commonly used ones are likeapplication/json
👀
How to fix CORS errors
Alright, now that you understand what's actually going on, let's talk about how to fix your CORS mess. Here’s how you can typically go about it:
Scenario: You’re making an API request in the browser from example.com
to api.example.com/posts
and you ran into a CORS error.
CORS errors should primarily be handled on the backend side, not client-side workarounds.
CORS Configuration
The first thing you should check is if you/your team owns or controls the API server (i.e. api.example.com
in this case). If you do — awesome! Here's how you can make it happen:
- To enable CORS on the server side, configure your API server to include the necessary CORS headers in its responses
- This is typically done by setting up CORS middleware or configuring the server framework to handle CORS
What CORS response headers should I add?
For example, these headers are to be added to your API server's HTTP response to enable CORS for requests originating from https://example.com
:
Header | Description | Must-Have | Example Value |
---|---|---|---|
Access-Control-Allow-Origin | Specifies the allowed origin. | Yes | https://example.com |
Access-Control-Allow-Methods | Specifies the allowed HTTP methods. | Yes | GET , POST , OPTIONS |
Access-Control-Allow-Headers | Specifies the allowed headers. | Yes | Content-Type , Authorization , X-Custom-Header |
Access-Control-Allow-Credentials | Indicates if credentials are allowed. | No | true |
Access-Control-Max-Age | Specifies the cache duration for preflight responses. | No | 86400 (24 hours) |
Here is an example of how you might modify the code to add CORS headers to a response from a Node.js Express server:
Um… I don’t own the 3rd-party API server
If you don't control the API server, well, you do have a few choices.
Unless the API owners decide to open up their CORS policy, you'll have to find a workaround. Here are some example workarounds:
- Proxy Server (Recommended): you can proxy the requests through a proxy server (which you can self-host) e.g. CORS Anywhere
- CORS Browser Extensions: some browsers have extensions or plugins that allow you to bypass CORS restrictions during development. These extensions modify the browser's behavior by adding CORS headers to the requests. This should only be used for development and testing purposes
Key Takeaways
- Preflight requests are automatically issued by the browser (when conditions are met)
- CORS errors only happen with browser requests to different domains, not server-side applications.
- To fix CORS errors, implement CORS middleware on the server side
- If you lack control over the API server, consider solutions like proxying requests or using third-party services, but keep security in mind
Happy coding, and may your requests always find their way around the CORS maze!