What is CORS? 5-minute explanation

What is CORS? 5-minute explanation
Photo by Will Porada / Unsplash

You coded a backend and now you want to connect your frontend app to your backend, but then you get this weird error:

What the hell is CORS?

CORS is an abbreviation for "Cross-Origin Resource Sharing".

This is a mechanism enabling a website at one URL to request data from another URL. This has been a great source of frustration for both front-end and back-end developers.

For example, you might have attempted to incorporate an image from a distinct URL into your web app. Then you encounter the issue of a broken image because of this CORS error.

Another scenario arises when your web app tries to retrieve data from API. When you execute a request, it results in a CORS error appearing in the console.

This occurs because the browser enforces the "Same Origin Policy". This policy is a fundamental component of its security framework.

This policy allows a website to request images from its own URL. However, it imposes restrictions on content retrieval from external URLs. Unless specific conditions are satisfied.

Behind the scenes

When the browser initiates a request, it includes the Origin header in the request message:

{"Origin": "http://localhost:3000"}

If this request is directed to a server with the same origin, it's ok. It is allowed by the browser without any inquiries.

However, if the request is directed to a different URL, it is categorized as a cross-origin request.

In such instances, upon returning the response, the server adds the Access-Control-Allow-Origin header:

{"Access-Control-Allow-Origin": "http://localhost:3000"}

The value of this header must correspond to the origin header in the request. Alternatively, it can be a wildcard.

Wildcard allows any URL to initiate a request, as demonstrated below:

{"Access-Control-Allow-Origin": "*"}

If the origins do not match, then the browser will jump in. It will prevent the response data from being shared with the client who makes a request.

This leads to an error displayed in the browser, but for security reasons, there is very limited information about what went wrong:

How to fix the error?

Long story short, the fix must be implemented at the server level.

If you lack control over the server, there's nothing you can do. But, if you can control the server, there is a fix with configuration. This configuration involves ensuring the server responds with an appropriate header.

For example, in a simple NodeJS Express server, this configuration can be done like this:

const express = require('express');
const cors = require('cors')
const app = express();
const port = 5000;

app.use(cors({origin: "https://mensurdurakovic.com"}));
 
app.get('/api/data', (req, res) => { 
  res.json({ message: 'Hello from the server!' });
});
 
app.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});

You can use the CORS npm package or code the middleware yourself.

With this line:

app.use(cors({origin: "https://mensurdurakovic.com"}));

you instruct your server to include CORS headers on every request.

Now, there are specific HTTP requests, such as PUT. Or any request featuring non-standard HTTP headers. These must undergo special treatment.

These will need to be pre-flighted. Just like on the security check at the airport to make sure that the passenger is safe to fly. Here it's done to ensure the safety and legitimacy of the HTTP request.

Similarly, the browser intuitively determines when to initiate a pre-flight. This is done with an initial request using the OPTIONS header.

The server issues a response indicating permission: "Okay, I authorize this origin to make requests using the following methods."

After this, the subsequent main request can proceed without the concern of rejection.

It looks like this:

Keep in mind even with pre flighted request, the server can respond with the Access-Control-Max-Age header:

{"Access-Control-Max-Age": 172800}

which will allow the browser to cache the preflight for a certain amount of time. In the example above it will be valid for 48 hours.

So, other than Access-Control-Allow-Origin property, you can define others:

  • Access-Control-Allow-Methods - set of methods you want to allow, like PUT, PATCH, DELETE, etc
  • Access-Control-Allow-Headers - like "Content-Type", "Authorization", etc
  • Access-Control-Max-Age - maximum age for a pre-flight request
  • Access-Control-Expose-Headers - includes the designated headers in the whitelist, granting permission for JavaScript in browsers to access them.
  • etc.

Final words

So if you are facing a CORS error:

  • open the browser network tab, find the response,
  • click on "Headers"
  • look for the Access-Control-Allow-Origin header:

What you can do:

  • If you don't see the Access-Control-Allow-Origin header, turn on CORS on your server, as explained above.
  • If the header is there, make sure it matches the origin you're requesting from.
  • If it went through pre-flight, it might restrict certain HTTP methods. Or maybe restrict headers in the request. Check if those are properly configured on the server.

Sources: