DEV Community

Akash Shukla
Akash Shukla

Posted on

CORS: Why It Exists, How It Works & How to Fix Common Issues

Hello! Today we are gonna talk about CORS. It’s the most common browser security rule, yet most devs only understand half of it. which is called Cross-Origin Resource Sharing. It is one of those things almost every frontend and backend developer faces while working with APIs.

Many developers think CORS is a backend issue, but actually it is a browser-side security rule which requires proper server configuration as well. Before understanding how to fix CORS issues, first lets understand why it exists and why browsers introduced it.


Why CORS Exists

CORS policy was introduced and adopted by browsers in the early 2010s to make the web more secure.

Before CORS, websites could potentially make unauthorized requests to other websites and access sensitive user data. Browsers needed a secure way to control how resources are shared between different origins.

CORS mainly exists to help prevent unauthorized data access, credential leakage, unsafe cross-origin communication, and CSRF-like attacks.

One important thing to understand is that CORS is enforced by browsers only.

That means browser requests can be blocked by CORS, but backend-to-backend requests are not affected. Postman does not care about CORS, and Node.js servers also do not care about CORS. That is why APIs sometimes work perfectly in Postman but fail inside the browser.

Honestly this confuses me almost but not now. let's understand a bit deeper side of it.


Same-Origin Policy

By default, browsers follow something called the Same-Origin Policy. This means a website can only access resources from the same origin unless the server explicitly allows it.

Now, An origin is made of 3 things:

  • Protocol
  • Domain/Hostname
  • Port

If any one of these changes, the origin becomes different.

Examples:

Initially I used to think only domain matters, but even changing just the port makes browser treat it as a completely different origin. So if frontend and backend origins are different, browser applies CORS rules.


How CORS Actually Works

Many developers think CORS completely blocks the request, but technically that is not fully correct.

In many cases browser still sends the request. But if server does not allow that origin, browser blocks frontend JavaScript from accessing the response.

So CORS is basically a mutual agreement between browser and server.

Browser asks:

“Can this frontend access your resources?”

And server responds using special headers. If server says yes, browser allows frontend to read the response. Otherwise browser blocks it for security reasons.


Important CORS Headers

There are some important headers that servers use to communicate with browsers.

Honestly, initially these headers looked scary But once you understand what each one actually does, CORS becomes much easier.

Access-Control-Allow-Origin

This tells browser which frontend origins are allowed.

Example:

```http id="9dz68t"
Access-Control-Allow-Origin: http://localhost:3000




This means only that frontend can access the resources.

---

## Access-Control-Allow-Methods

This tells which HTTP methods are allowed.

Example:



```http id="yjlm2v"
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Enter fullscreen mode Exit fullscreen mode

If you only allow GET requests, then frontend can basically only read data. No update or delete operations will happen.


Access-Control-Allow-Headers

This tells browser which custom headers frontend is allowed to send.

Example:

```http id="ywp4o9"
Access-Control-Allow-Headers: Authorization, Content-Type




Without this, browser may block requests containing custom headers. I personally got stuck once because I was sending Authorization headers from frontend but forgot to allow them from backend 😭

---

## Access-Control-Allow-Credentials

This is used when cookies or authentication data need to be shared between different origins.

Example:



```http id="dc3r59"
Access-Control-Allow-Credentials: true
Enter fullscreen mode Exit fullscreen mode

This basically tells browser that this request is allowed to include credentials like cookies.

Think of it like browser asking:

“Should I carry cookies with this request?”

And server replying:

“Yes, you can bring them.”


withCredentials Flow

On frontend we usually send:

```js id="2k5n7x"
axios.get("http://localhost:5000", {
withCredentials: true
})




This tells browser to include cookies, authentication credentials, and session data with the request.

If we do not explicitly tell browser `withCredentials: true`, browser will not carry cookies with the request even if cookies already exist.

And server also needs to allow it by sending:



```http id="njlwmv"
Access-Control-Allow-Credentials: true
Enter fullscreen mode Exit fullscreen mode

Basically both sides need to agree.

Browser says:

“I will carry cookies.”

And server says:

“Okay, I accept requests with credentials.”

One very important thing is that:

```http id="5c6l9o"
Access-Control-Allow-Origin: *




cannot be used together with credentials. You must specify the exact frontend origin.

This is another very common issue developers hit while setting up authentication.

---

# Preflight Requests

This is one of the most important CORS concepts many beginners miss.

Whenever browser sends requests like POST, PUT, DELETE, PATCH, requests with Authorization headers, or requests with custom headers, browser may first send an OPTIONS request before the actual request.

This is called a preflight request.

Browser basically asks server:

> “Is this request allowed?”

Server then responds with:



```http id="kr0vnd"
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Enter fullscreen mode Exit fullscreen mode

If everything looks valid, browser sends the actual request.

Have you ever noticed the preflight requests in network tab and thought:

“Who is making this extra request?”

But actually browser itself sent this for security checking before sending the real request.


Common CORS Errors

1. Missing Access-Control-Allow-Origin

This is the most common issue. Server forgot to allow frontend origin.


2. Credentials + Wildcard Error

This will fail:

```http id="tz3a2h"
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true




Browsers block this for security reasons.

---

## 3. Missing Headers Permission

If frontend sends:



```http id="3frykk"
Authorization
Enter fullscreen mode Exit fullscreen mode

but server does not allow it inside:

```http id="2nz7ko"
Access-Control-Allow-Headers




browser blocks the request.

---

# Fixing CORS in Express.js

You might be already using this modern packages like cors in npm which handles most of this automatically.

Example:



```js id="u3k6ru"
import cors from "cors";

app.use(cors({
  origin: "http://localhost:3000",
  credentials: true
}));
Enter fullscreen mode Exit fullscreen mode

This handles most common CORS configurations properly.

Most of the time, issue is not the cors package itself. Usually it is wrong origin, missing credentials, missing headers configuration, or frontend and backend not agreeing properly.


Final Thoughts

CORS is not a bug.

It is a browser security mechanism designed to safely allow or restrict resource sharing between different origins. Browser enforces the rules, while server provides permission through headers.

Once you understand Same-Origin Policy, origins, preflight requests, credentials, and browser vs server responsibility, CORS becomes much easier to debug and understand.

That's it for now.

Some day we will also talk deeply about:

  • How cookies are actually passed in CORS
  • How HTTPS affects secure cookies
  • CSRF and XSS attacks
  • SameSite cookies
  • Authentication flows with CORS
  • Why your browser is dropping the cookies and not saving in browser.

because that is where things become even more interesting.

Top comments (0)