๐ŸŒ Detecting your locationโ€ฆ

How to Fix CORS Error ‘No Access-Control-Allow-Origin’ Header in 2026

โฑ๏ธ5 min read  ยท  946 words

You make a request from your frontend to an API and the browser blocks it with: Access to fetch at '...' from origin '...' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. This is one of the most common and misunderstood errors in web development. Here is what actually causes it and how to fix it correctly.

What CORS Actually Is

CORS (Cross-Origin Resource Sharing) is a browser security mechanism. When your JavaScript on https://app.example.com makes a request to https://api.other.com, the browser considers it a cross-origin request and requires the server to explicitly permit it via response headers. If the server does not send an Access-Control-Allow-Origin header that includes your origin, the browser blocks the response โ€” even if the server processed the request successfully.

Key insight: CORS is enforced by the browser, and the fix lives on the server, not in your frontend code. You cannot fix a CORS error by changing your fetch call alone.

Fix 1: Configure the Server to Send the Header

The correct fix is to make the API respond with the right CORS headers. In Express, use the cors middleware:

const cors = require('cors');

app.use(cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true
}));

Set origin to your frontend’s exact origin. Do not use a wildcard * in production if you send credentials (cookies or auth headers) โ€” browsers reject the combination of Access-Control-Allow-Origin: * with credentials: true.

Fix 2: Handle Preflight (OPTIONS) Requests

For any request that is not a simple GET/POST โ€” for example one that sends Content-Type: application/json or an Authorization header โ€” the browser first sends a preflight OPTIONS request asking permission. Your server must respond to it with the appropriate headers. The cors middleware above handles this automatically, but if you set headers manually, you must handle OPTIONS explicitly:

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://app.example.com');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  if (req.method === 'OPTIONS') {
    return res.sendStatus(204); // Respond to preflight, do not fall through
  }
  next();
});

A common mistake is failing to respond to the OPTIONS preflight โ€” the browser sends it, gets no valid CORS response, and blocks the real request before it is ever made.

Fix 3: Match the Origin Exactly

The origin must match precisely โ€” protocol, domain, and port all count. These are all different origins to the browser:

Origin Why It Differs
http://localhost:3000 Different protocol from https
https://localhost:3000 Different protocol from http
https://example.com Different port from :3000
https://www.example.com www subdomain differs from apex

If your allowed origin is https://example.com but your app loads from https://www.example.com, CORS blocks it. Allow every origin the app actually uses, or normalize to one.

Fix 4: Use a Dynamic Origin for Multiple Frontends

If several origins need access (staging, production, localhost), validate against an allowlist instead of hardcoding one:

const allowed = [
  'https://app.example.com',
  'https://staging.example.com',
  'http://localhost:3000'
];

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

Fix 5: For Local Dev, Use a Proxy

During development, you can sidestep CORS by proxying API requests through your dev server so they appear same-origin. In Vite:

// vite.config.js
export default {
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:5000',
        changeOrigin: true
      }
    }
  }
};

Now your frontend calls /api/... on its own origin and the dev server forwards it. This is a development convenience, not a production fix โ€” production still needs proper CORS headers on the API.

What NOT to Do

Do not reach for browser extensions that disable CORS, and do not slap Access-Control-Allow-Origin: * on everything to make the error disappear. The wildcard exposes your API to every site on the internet and breaks credentialed requests. CORS is a security feature โ€” configure it correctly rather than disabling it.

Frequently Asked Questions

Q: Why does the request work in Postman but not the browser?
A: Postman does not enforce CORS โ€” only browsers do. The request reaching the server proves the server works; the browser blocks the response because the CORS headers are missing. Fix the headers on the server.

Q: Can I fix CORS from the frontend?
A: No. CORS headers must come from the server responding to the request. The only frontend-side workaround is a dev proxy, which makes requests same-origin during development.

Q: Why does my preflight OPTIONS request fail?
A: The server is not responding to OPTIONS with the correct CORS headers and a 2xx status. Ensure your CORS middleware runs before your routes, or handle OPTIONS explicitly and return 204.

Q: Why does credentials: true break with origin ‘*’?
A: Browsers forbid sending credentials (cookies, auth) when the allowed origin is the wildcard *. Specify the exact origin instead when you need credentials.

Q: The header is there but it still fails. Why?
A: Check that the origin matches exactly (protocol, domain, port), that OPTIONS preflight is handled, and that a proxy or CDN in front is not stripping the header. Inspect the actual response headers in the Network tab.

Conclusion

The “No Access-Control-Allow-Origin header is present” error means the browser blocked a cross-origin response because the server did not permit your origin. The fix is always on the server: send the correct Access-Control-Allow-Origin header, handle the OPTIONS preflight, match the origin exactly, and never use a wildcard with credentials. For local development, a dev proxy avoids the issue cleanly. Once the server returns the right headers for your exact origin and responds to preflight requests, the error disappears and your requests go through.

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work โ€” which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

โœ๏ธ Leave a Comment

Your email address will not be published. Required fields are marked *