CORS Finally Explained — Simply

Oleks Gorpynich
Level Up Coding
Published in
4 min readMar 24, 2024
Chat GPT Generated Image
Source

Seen the above before? Probably… and probably quite a lot…

There are millions of articles explaining how to fix the error above, but what exactly is this “Cross-Origin Resource Sharing” (CORS) thing, and why does it even exist?

Why???

Let's begin by first answering the question of why through a scenario and how it’d play out at different points in time.

Imagine this: you log into bank.com, which is your banking service. After logging in, a “session cookie” is stored in your browser. (Session cookies basically tell the server behind bank.com that your browser is now logged into your account). All future requests to bank.com will now contain this cookie, and it can respond properly knowing you are logged in.
Ok, so now you decide to check your mailbox. You see a suspicious email, and of course, you decide to click the link inside which sends you to attack.com. Next, this website sends a request to bank.com to get your banking details. Keep in mind that bank.com still thinks you are logged in because of that session cookie… that cookie is stored on your browser. For the servers behind bank.com, it just looks like you requested your banking details normally, so it sends them back. Now attack.com has access to these and stores them elsewhere maliciously.

People realized this was bad, so browsers adopted an SOP (Same-Origin Policy) where if your browser notices that you are trying to make requests to bank.com from anywhere other than bank.com they will be blocked. Now, this is a key thing to realize — this is a browser-based policy. bank.com really has no way to tell where a request comes from, so it can’t protect much against attacks like CSRF. The browser you are using steps in and basically says that if you seem to be trying to request details for an origin (scheme + domain name + port, https//foo.com:4000, http//bar.org:3000, etc… Basically the URL), it will only send those requests for same origins.

Now, this was great and all, but it was incredibly limiting. I mean, public APIs wouldn’t work at all. You couldn’t request data from them unless you used some sort of proxy solution.

CSRF

Here’s the thing: servers can sorta tell where a request came from. There is the “Origin” header, which requests should have, showcasing what origin made a request. For instance, in the above example, the request would look something like this.

Request to -----> bank.com
{
Headers: { Origin: http://attack.com }
}

bank.com in theory, should be checking this to make sure it only responds to requests where the origin makes sense. And it usually does, so SOP seems kinda limiting.
This is where CORS comes in.

CORS

When a web application from example.com attempts to request resources from bank.com, the browser automatically includes an Origin header in the request, indicating where the request originates from (example.com). Here's the crucial part: Instead of outright blocking such cross-origin requests under the SOP, bank.com's server can inspect this Origin header and decide whether to allow or deny the request based on its own CORS policy.

If bank.com considers example.com trustworthy or the resource being requested is meant to be publicly accessible, it can respond with specific CORS headers, such as Access-Control-Allow-Origin, indicating which origins are permitted to access the resource. This header might be set to http://example.com, explicitly allowing this origin, or * for public resources that any origin can access.

Of course, the browser facilitates all this. If any of it is wrong, you’ll get that nasty error.

Now… what if the request doesn’t have the Origin header? What if it has a bunch of other headers and doesn’t use one of the basic HTTP methods?

In these situations, the handling of CORS becomes a bit more intricate as it is no longer a “simple request”. This is where the concept of "preflight" requests in CORS comes into play.

Preflight

For certain types of requests that could potentially modify data on the server—those that use HTTP methods like PUT, DELETE, or use headers that are not automatically included in every request—browsers will first send a "preflight" request before making the actual request. This preflight request is an HTTP OPTIONS request, and its purpose is to check with the server whether the actual request is safe to send.

The preflight request includes headers that describe the HTTP method and headers of the actual request. Here’s what happens next:

  1. Server Response: If the server supports the CORS policy and the actual request, it responds to the preflight request with headers indicating what methods and headers are allowed. This might include headers like Access-Control-Allow-Methods and Access-Control-Allow-Headers.
  2. Browser Decision: Based on the server's response to the preflight request, the browser decides whether to proceed with the actual request. If the server's response indicates that the request is allowed, the browser sends it; if not, the browser blocks the request, and you'll see an error related to CORS.

Conclusion

Now, hopefully, you understand a little bit more about CORS. I think the most important thing to realize is this is all browser policy, and your server must be coded to comply with it. It is in place to keep you safe. If you are using Chrome, you shouldn’t worry as much about clicking the wrong links (of course, you still should worry a little :D). However, this isn’t a foolproof policy. If you use some 3rd party browser that doesn’t comply with standards, all this would be thrown away. That is why one must remain careful with what software they use!

--

--

Aspiring developer. I write about AI, ML, occasional Web Dev, and Philosophy :) Short story account - https://medium.com/@oleksandr.gorpynich