Access blocked by CORS Policy: What’s CORS and what should you do?

Karisse Khoo
FAUN — Developer Community 🐾
5 min readJun 28, 2022

--

Image by Undraw

You may have seen terms like Cross-Origin Resource Sharing (CORS) and Same-Origin Policy (SOP) being mentioned pretty often but, what exactly are they? Before getting into the meat of this article, just thought I’d share one great mindset shift.

Don’t just fix the symptom, fix the root cause of the problem.

I’m sure many of us have been guilty of this at some point in our lives; I’m guilty of it myself, but it’s something in the works. By addressing the root cause, we can avoid implementing “band-aid” solutions that may lead to technical debt overtime. That being said, if this perilous-looking error message looks all too familiar to you, this article will attempt to make sense of it by analysing how SOP and CORS apply in Client-Side Rendering, how they differ in Server-Side Rendering, and, most importantly, how we can resolve the error.

👋 If you want to follow along, here’s the GitHub repo which you can fork to help you get started!

Unravelling Same-Origin Policy

To understand why we encounter the CORS error, we need to know what SOP is. Browsers implement SOP to restrict access to data from one origin to another by default. Therefore, http://localhost:3000 is unable to make a cross-origin request to http://localhost:4000. This article here gives a really good overview of determining what should be deemed as same-origin and cross-origin.

What exactly is a preflight request?

Let’s break down the error message further. Notice that in the error, it mentioned “preflight request doesn’t pass access control check”. If we take a look at the diagram below, we can see how a request is processed under the hood: if the preflight request check is successful, the browser sends a preflight OPTIONS request before sending the actual request to the server.

Why is there a need for preflight requests?

By calling an API to http://localhost:4000 from http://localhost:3000, we are attempting to access a restricted resource. The CORS preflight request is triggered to protect servers from receiving unexpected cross-origin requests. Here, we see that the preflight request has failed as the server did not specify CORS and has fallen back to SOP.
Note: If you do not see the OPTIONS request under your network tab, you may want to experiment using Firefox to enable that visibility.

Otherwise, according to SOP, the browser will send the actual request without the need for a preflight request.

Addressing the root cause

Now that we’ve covered our bases, we know that the browser is rejecting the request because we are attempting to access a restricted resource from another origin. Let’s fix the root problem!

We’ll need to relax the SOP by whitelisting http://localhost:4000 on the server to gladly receive cross-origin requests from http://localhost:3000. To do that, we need to enable CORS on our server and set Access-Control-Allow-Origin: 'http://localhost:3000'.

A word of caution ⚠️: Although you can use the * wildcard to accept request from all origins, it is not recommended especially if your APIs are not meant for public use as it could pose security risks.

After we’ve enabled CORS on our server, notice that our preflight OPTIONS request returns status 204 with Access-Control-Allow-Origin attached to its headers. The browser then proceeds to send the actual request and return a successful response back to the client.

What about Server-Side Rendering?

In Server-Side Rendering (SSR), you may be surprised that we’re able to retrieve data from a server without CORS enabled. Why is that so? Recall that we’ve touched on how the browser implements SOP and is responsible for making the actual API request to the server. This is the result of Client-Side Rendering (CSR).

Whereas for SSR, as its name suggests, we are fetching data on the server-side before the page is loaded. This means that the actual request will no longer be sent by the browser hence, SOP does not apply. Notice that in SSR, there are no requests sent by XHR (browser-level API) but rather, we are rendering the HTML content with the browser.

To put simply the difference between SSR and CSR in bite-size:

  • SSR — Calls the API before the page loads
  • CSR — Calls the API after the page loads thus actual requests are made from the browser

Does SOP cover all grounds related to web security?

We’ve talk about how SOP and CORS can help prevent unwarranted requests to protect the server. So to answer the burning question: No, SOP does not cover all grounds related to web security. To help dip your toe in the water a little, the web application can still be prone to attacks such Cross-Site Request Forgery (CSRF), Cross-Site Scripting (XSS) and many more. But these are the topics that deserve a post on its own.

Before we end off… Let’s do a quick recap!

Browsers implement SOP to restrict cross-origin requests and prevent unwarranted requests made to the server with the help of CORS preflight requests. We need to enable CORS and whitelist the list of URLs that the server expects in the allowed origins header to relax SOP. But since SOP does not exactly guard against web attacks, we must remain vigilant by implementing additional security measures.

Thanks for reading this far! Hope you’ve learnt a thing or two from this article. If you would like to see more of topics related to software development, you can give me a follow or subscribe to me and be notified whenever I have a new article up!

👏 This article was made possible by picking the brains of these authors

If this post was helpful, please click the clap 👏 button below a few times to show your support for the author 👇

🚀Developers: Learn and grow by keeping up with what matters, JOIN FAUN.

--

--

Full-stack developer based in Singapore. Knowledge is wealth, I write to share about all things related to Software Development https://karissekhoo.netlify.app/