# CORS 101: What It Is, Why It Matters, and How It Works

It was 2AM, the air thick with anticipation. We were finally ready to deploy our website—the gateway for users to start registering on our new portal. After days of testing everything locally, I took a deep breath and hit deploy. Moments later, I visited the production URL, filled in the registration form, and clicked Register.

And then—*boom*. “Some error occurred.” My heart sank.

I rushed to check the server logs, expecting a stack trace or at least *something*. But... nothing. No logs. No request. It was as if the request had vanished into thin air.

Puzzled, I opened Postman and sent the exact same request. It worked perfectly. Now I was more confused than ever. Why would Postman reach my servers, but the website—our actual frontend—not even trigger a server log?

Then I opened the browser console, and there it was. A barrage of errors screaming back at me: **CORS errors**.

That night, I learned (the hard way) about something every web developer inevitably runs into—**Cross-Origin Resource Sharing**, or CORS. If you’re deploying a frontend that talks to an API on a different domain or port, understanding CORS is non-negotiable

**So….. What is CORS and Why is it so important ?**

**CORS** stands for **Cross Origin Resource Sharing** and it is a browser security feature that controls how resources are requested across ***different origins.***

This begs another question: **What exactly is an Origin ?**

**Origin**, as the word suggests, is used to identify the **source** or **origination point** of a request. We all know that a **URL** is a string used to locate resources on the internet—but the **origin** is just a part of that URL.

It was first introduced by **Netscape** and is now part of the **HTML Living Standard**, maintained by **WHATWG** (don’t ask... it’s a long story).

An **origin** is defined as a combination (technically, a *tuple*) of the following three things:

* **Scheme** (the protocol, e.g., `http`, `https`)
    
* **Hostname** (the domain, e.g., [`example.com`](http://example.com))
    
* **Port** (e.g., `80`, `443`, or custom ones like `3000`)
    

So two URLs might *look* similar, but if any one of these components differs, the browser will treat them as **different origins**—and that’s where **CORS** comes into play.

Let us take a real world example to understand origins.

* `https://example.com`
    
* `http://example.com`
    
* `https://example.com:8000`
    
* `https://api.example.com`
    

At a glance, these might feel like the *same* site - but from a browser’s perspective these are **four completely different origins.**

Here’s why:

| URL | Scheme | Hostname | Port | Different Origin ? |
| --- | --- | --- | --- | --- |
| `https://example.com` | `https` | `example.com` | 443 | — |
| `http://example.com` | `http` | `example.com` | 80 | ✅ (different scheme) |
| `https://example.com:8000` | `https` | `example.com` | 8000 | ✅ (different port) |
| `https://api.example.com` | `https` | `api.example.com` | 443 | ✅ (different hostname) |

So even if your frontend is served from [`https://example.com`](https://example.com) and your backend is on [`https://api.example.com`](https://api.example.com), that’s a **cross-origin** request—and that’s when CORS rules apply.

Now that we know what CORS is and how does it detect different *Origins.* let us understand the reason behind it.

## **Why is CORS important ?**

Let us try to understand this with a scenario:

Imagine you are the owner of a bank and you have a website at `https://bank.com`; this website is the login portal for all your customers and allows them to access there account information and details. Now, there is a an evil guy, let’s call him John. John knows that if he can somehow make the user think that his website also let’s the user access the account he will be able to steal all the information.

So he comes up with an evil plan; He creates a website at `https://evil.com` and this website sends requests to `https://bank.com` on behalf of the users. Now his website is posing as the bank’s official website because it is getting all the accurate data from `https://bank.com`

As the owner of the bank you want to prevent this. Now if CORS weren’t present you would have to validate that the Origin of the request header matches the one of your site and this validation would have to be setup at each endpoint of your website.

CORS is this validation layer that you just implemented. CORS is important because it allows website owners to specify who and what can access the website / resource.

## How does it work ?

**CORS** relies on the mechanisms in the browser using which they send “preflight” request to the web server hosting the **cross origin resource,** in order to check if the server will allow the actual request.

In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request. This preflight request can be considered a very light weight version of the original request as it contains no payload or data that the original request might transfer.

How does the server tell if they wanna allow a specific request or not ?

Well in response to the CORS preflight request. The server sends a response containing the headers that tell **Who can access, What can be accessed, What methods are allowed, How to send data** etc

### Rules for a preflight request:

A preflight request is sent when the actual request does not meet the criteria for a ***“simple request”.*** A request is considered **simple** if it follows these rules:

1. **HTTP Methods:** The request may use only simple HTTP verbs (methods)
    

* `GET`
    
* `POST`
    
* `HEAD`
    

2. [**CORS-safelisted request headers**](https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header): The request can only contain certain headers that are a part of the CORS-safelisted headers.
    

* `Accept`
    
* `Accept-Language`
    
* `Content-Language`
    
* `Content-Type`
    
* `Range` (only with a single range header value, e.g. `bytes=127` or `bytes = 127-255`)
    

3. **Content-Type restrictions**: If the `Content-Type` header is set, it can only use the following [media types](https://developer.mozilla.org/en-US/docs/Glossary/MIME_type):
    

* `application/x-www-form-urlencoded`
    
* `multipart/form-data`
    
* `text/plain`
    

If a request follows these conditions, then it is considered a **simple request** and does not trigger a preflight check. If the request includes an non-simple methods or headers (like custom headers), it will trigger a **CORS preflight.**

Let’s take a closer look at how the preflight request works in this scenario.

Let’s say we have to fetch some doc from our backend. Our frontend is hosted on `foo.site` and backend is on `bar.site`.

Imagine we want to fetch some document from our backend. Our frontend is hosted on `foo.site` , and the backend is located at `bar.site`. Here’s what the request might look like:

```javascript
const request = fetch("https://bar.other/doc", {
  method: "GET"
  headers: {
    "Accept": "application/json",
    "Authorization": "Bearer 12kdlfajlfja"
  }
});

request.then((response) => {
  if (response.ok) {
    return response.json()
  }
  throw new Error("invalid response")
})
.then((data) => {
    console.log(data)
});
```

In this code, we are sending an `HTTP` request from `foo.site` to fetch the resource `/doc` from `bar.site`. Since the frontend is on `foo.site` and the request is going to `bar.site` this qualifies as a Cross-Origin Request. Additionally the above request includes an `Authorization` header which is not a **CORS-safelisted request header**. As a result, a **preflight request** will be sent by the browser to check if the request is allowed.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1744830461702/7b05771d-2f90-4010-b796-3e090f4f2505.png align="center")

In the above exchange we can see that there is an `OPTIONS` request that is sent before the actual `GET` request. This `OPTIONS` request is the preflight request that is sent by the browser. We can also see that the in response to the `OPTIONS` request, the server sent some headers:

* `Access-Control-Allow-Origin` - This tells the browser **who can access** ( here `*` means all)
    
* `Access-Control-Allow-Methods` - This tells the browser **what methods are allowed**
    
* `Access-Control-Allow-Headers` - This tells the browser **what headers are allowed**
    

In summary, the preflight `OPTIONS` request serves as a ***security*** measure enforced by the browser to verify that the actual request is safe to send. By examining the server's response headers—such as `Access-Control-Allow-Origin`, `Access-Control-Allow-Methods`, and `Access-Control-Allow-Headers`—the browser ensures that the cross-origin request complies with the server's policies. If the headers meet the browser's requirements, the actual request proceeds; otherwise, it is blocked. This mechanism is a key part of Cross-Origin Resource Sharing (**CORS**) and helps protect both servers and clients from unauthorized access and potential security risks.

## TL;DR

**CORS** might feel a bit mysterious at first, but it’s essentially a browser-enforced security measure that helps protect users from cross-site attacks. The **preflight request** is a key part of that system—it’s the browser’s way of asking the server, *“Hey, is it okay if I send this kind of request?”*

By understanding what triggers a preflight and how the server should respond, you can confidently build cross-origin applications without running into the dreaded *“CORS error”* wall. Whether you're sending custom headers, using different HTTP methods, or handling third-party APIs, knowing how CORS works behind the scenes will help you troubleshoot faster and design better APIs.

In the end, it’s all about communication—between browser and server—just a polite check-in before doing something a little out of the ordinary.
