DEV Community

Rishi
Rishi

Posted on

CORS: The Developer’s Nightmare: A Scenario-Based Guide to Fixing it Without *

CORS: The Developer’s Nightmare: A Scenario-Based Guide to Fixing it Without *

We’ve all been there. You’ve spent hours perfecting your Node.js API and your React frontend. You trigger your first fetch() request, and instead of data, you get a wall of red text in the console:

"Access to fetch at 'https://www.google.com/search?q=api.mysite.com' from origin 'mysite.com' has been blocked by CORS policy..."

In a moment of frustration, many developers reach for the "nuclear option": setting Access-Control-Allow-Origin to *. While this makes the error go away, it’s the security equivalent of leaving your front door wide open because the lock was sticking.

Here is how to navigate the most common CORS nightmares like a pro.


What is CORS actually doing?

Cross-Origin Resource Sharing (CORS) is not a bug; it is a browser security feature. It prevents a malicious website from making requests to your API on behalf of a user.

The browser uses a Preflight Request (an OPTIONS call) to ask the server: "Hey, is this domain allowed to talk to you?" If the server doesn't explicitly say "Yes," the browser kills the request.


Scenario 1: The "I have multiple environments" Problem

The Setup: You have a local development server (localhost:3000), a staging site, and a production site. You need all of them to access your API.

The Wrong Fix:

// Hardcoding one domain breaks the others
res.setHeader('Access-Control-Allow-Origin', 'https://mysite.com');

Enter fullscreen mode Exit fullscreen mode

The Pro Fix:
Create a "Whitelist" and check the incoming Origin header against it.

const whitelist = ['http://localhost:3000', 'https://staging.mysite.com', 'https://mysite.com'];

const corsOptions = {
  origin: function (origin, callback) {
    if (whitelist.indexOf(origin) !== -1 || !origin) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  }
};

Enter fullscreen mode Exit fullscreen mode

Note: !origin allows tools like Postman or server-to-server requests to still function.


Scenario 2: The "I need to send Cookies" Problem

The Setup: You are using credentials: 'include' in your fetch request because you need to send session cookies or HttpOnly JWTs.

The Nightmare: When you use credentials, the browser strictly forbids the use of *. If you try it, the request will fail.

The Fix: 1. Reflect the Origin: You must echo back the specific origin of the requester.

  1. Allow Credentials: Set the Access-Control-Allow-Credentials header to true.
// Example in Express.js
app.use(cors({
  origin: 'https://mysite.com',
  credentials: true
}));

Enter fullscreen mode Exit fullscreen mode

Scenario 3: The "Custom Headers" Problem

The Setup: You are sending a custom header for tracking or versioning, such as X-API-Version: v1.

The Nightmare: Even if the origin is allowed, the browser will block the request because it considers X-API-Version a "non-standard" header.

The Fix:
You must explicitly tell the browser that this specific header is safe to read.

Access-Control-Allow-Headers: Content-Type, Authorization, X-API-Version

Enter fullscreen mode Exit fullscreen mode

Summary Checklist: Fixing CORS the Right Way

Action Why?
Check the trailing slash https://mysite.com and https://mysite.com/ are different origins.
Match the Protocol http and https are not the same in the eyes of CORS.
Verify Port Numbers localhost:3000 is a different origin than localhost:4000.
Use a Middleware Use established libraries like the cors npm package instead of manual headers to avoid typos.

The Ultimate Rule

CORS is a browser-only concept. If you are still seeing "Access Blocked" after following these steps, check your server-side logs. Sometimes a 500 Internal Server Error on your API causes the CORS headers not to be sent, leading the browser to report a CORS error instead of the actual backend crash.

Top comments (0)