StackDevLife
Cover image for: CORS Isn't a Bug - It's Your API Trying to Warn You (And You Ignored It)
Back to Blog

CORS Isn't a Bug - It's Your API Trying to Warn You (And You Ignored It)

Stop fighting CORS. Understand preflight requests, credentials, wildcard mistakes. CORS isn't a bug—it's your API warning you about real security issues.

SB

Sandeep Bansod

April 22, 202612 min read
Share:

Most developers' first reaction to CORS:

"Why is this blocking my request? It works in Postman!"

So you do what everyone does:

JavaScript
app.use(cors({ origin: "*" }));

…and move on.

Until one day, something breaks in production. Or worse — something should have been blocked… but wasn't.should have been blocked… but wasn't.

The First Time CORS Slaps You

The First Time CORS Slaps You
The First Time CORS Slaps You

A very real scenario:

  • Frontend: https://app.example.comhttps://app.example.com
  • API: https://api.example.comhttps://api.example.com

Everything works in Postman. But in browser:

Bash
Access to fetch at 'https://api.example.com' from origin 'https://app.example.com'
has been blocked by CORS policy

👉 You think: "API is broken"

👉 Reality: Browser is protecting the userBrowser is protecting the user

What CORS Actually Is (Without the Textbook Definition)

CORS is not a server feature.

👉 It's a browser security rulebrowser security rule

Server just says:

"I allow / don't allow this request"

Browser decides:

"Okay, I trust this… or I block it"

What's Really Happening Behind the Scenes

When your frontend calls API:

  • Browser adds:
HTTP
Origin: https://app.example.com
  • Server must respond with:
HTTP
Access-Control-Allow-Origin: https://app.example.com
  • If not?

👉 Browser blocks it

👉 Even if API returned 200

The Part Everyone Ignores: Preflight Requests

Before some requests, browser sends:

HTTP
OPTIONS /api/data

This is called:

👉 Preflight requestPreflight request

When does this happen?

  • POST, PUT, DELETE
  • Custom headers (AuthorizationAuthorization))
  • JSON content-type

Flow:

  1. Browser: "Can I send this request?"
  2. Server: "Yes / No"
  3. Then actual request is sent

👉 If your server doesn't handle OPTIONS → request never reaches your API logicOPTIONS → request never reaches your API logic

Cors Http Headers
Cors Http Headers

Real Mistakes Developers Make

1. Using * with credentials

JavaScript
app.use(cors({
  origin: "*",
  credentials: true
}));

👉 This DOES NOT work

Browser blocks it.

2. Ignoring credentials completely

If you use cookies:

JavaScript
fetch(url, {
  credentials: "include"
});

Then server MUST return:

HTTP
Access-Control-Allow-Credentials: true

3. Not handling OPTIONS

JavaScript
app.options("*", cors());

Without this:

  • Preflight fails silently
  • Dev thinks API is broken

4. Hardcoding localhost

JavaScript
origin: "http://localhost:3000"

👉 Works in dev 👉 Fails in production

5. Fighting CORS instead of understanding it

  • Disabling browser security
  • Using proxies blindly
  • Copy-pasting configs

Real-World Failure (Seen Too Often)

  • Dev tests API in Postman → works
  • Deploys frontend → fails
  • Adds * → partially works* → partially works
  • Adds cookies → breaks again

👉 Why?

Because:

Postman doesn't enforce CORS. Browser does.

What Proper CORS Setup Looks Like

Backend (Node.js / Express)

JavaScript
const allowedOrigins = [
  "https://app.example.com",
  "https://admin.example.com"
];

app.use(cors({
  origin: function(origin, callback) {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  credentials: true
}));

Headers You Must Understand

Cors Understanding Origin
Cors Understanding Origin

Access-Control-Allow-Origin (Who can access) | Access-Control-Allow-Methods (Allowed methods)

Access-Control-Allow-Headers (Allowed headers) | Access-Control-Allow-Credentials (Allow cookies)

How This Connects to Auth (JWT + Cookies)

This is where things get real:

If you use:

  • Cookies (HttpOnlyHttpOnly))
  • JWT + refresh tokens

Then:

  • 👉 CORS MUST allow credentials
  • 👉 Origin cannot be **

Otherwise:

  • 👉 Auth silently fails
  • 👉 Cookies not sent
  • 👉 Sessions break

The Mental Model That Changes Everything

Stop thinking:

"CORS is blocking my request"

Start thinking:

"Browser is asking: should this request be trusted?"

Practical Checklist (Do This Today)

  • ✅ Define allowed origins (no * in prod)* in prod)
  • ✅ Enable credentials if using cookies
  • ✅ Handle OPTIONS requestsOPTIONS requests
  • ✅ Match frontend + backend domains
  • ✅ Test in browser (not just Postman)

Final Thought

CORS errors are not bugs.

They are warnings.

"Something about this request is not safe"

Most developers ignore that warning. Good developers understand it.

Enjoying this article?

Get new articles, tips, and fixes delivered straight to your inbox — free, no spam.

Was this article helpful?

Let me know if this was useful — it helps me write more content like this.

Found this useful? Share it.

XLinkedInHN
SB

Sandeep Bansod

I'm a Front-End Developer located in India focused on making websites look great, work fast and perform well with a seamless user experience. Over the years I've worked across different areas of digital design, web development, email design, app UI/UX and development.

Comments

Leave a Comment

All comments are reviewed before publishing

0/2000

Email is private and never published

Related Articles

You might also enjoy these

Level up your dev skills — weekly

Practical tutorials, quick fixes, and tools that save you hours.Join developers who read Stack Dev Life every week. Free, no spam.