On this page
  1. What is CORS?
  2. Why does CORS only fail in the browser?
  3. What is a CORS preflight request?
  4. How do I fix a CORS error?
  5. Where AI coding assistants get CORS wrong
  6. Checklist
  7. FAQ
    1. What is CORS in simple terms?
    2. How do I fix a CORS error?
    3. Why does CORS only fail in the browser?
    4. Is CORS a security vulnerability?
    5. Should I disable CORS to make it work?
    6. Does CORS stop other people from calling my API?
  8. Related topics
  9. Sources
concept

What Is CORS (and Why Does Every AI-Generated App Hit It)?

CORS is the browser rule that blocks cross-origin requests without server permission. Learn why AI-generated apps hit it and how to fix it safely.

Quick answer

  • CORS (Cross-Origin Resource Sharing) is a browser rule that blocks your frontend from calling an API on a different domain unless that API opts in.
  • It is not a server restriction — curl and Postman bypass it entirely, which is why the same call works in one place and fails in the browser.
  • The fix is CORS response headers on the API server: Access-Control-Allow-Origin, plus Access-Control-Allow-Methods and Access-Control-Allow-Headers.
  • Allowlist your real origins. Access-Control-Allow-Origin: * breaks credentialed requests and, when paired with reflected origins, disables the protection entirely.

What is CORS?

Cross-Origin Resource Sharing (CORS) is a browser-enforced security mechanism that controls whether JavaScript running on one website is allowed to make a request to a different website. An “origin” is the combination of scheme, host, and port — so http://localhost:3000 and http://localhost:5173 are different origins even though they are the same machine.

When JavaScript makes a cross-origin request, the browser refuses to hand the response to the page unless the server explicitly permitted it with response headers. The default posture is deny, and the opt-in is per-origin, per-method, per-header. CORS is what stops any website you visit from quietly reading your web app’s authenticated API.

Where this bites vibecoders

The specific way this bites vibecoders is the AI-generated full-stack scaffold. A generated app almost always puts the frontend on port 3000, 5173, or 8080 and the API on 3001, 8000, or 8081 — two different origins. The app is then asked to “make it work,” and the assistant’s most common suggestion is to disable the browser’s security check or add a permissive header, rather than configuring the origin allowlist. It works, and the real protection is gone.

Why does CORS only fail in the browser?

CORS fails only in the browser because the browser is the only component that enforces it. When curl, Postman, Insomnia, or your own backend makes the request, no Origin header is attached and no policy check occurs, so the response comes back normally.

This produces the most confusing symptom in web development: an endpoint that returns perfect data in the terminal, passes Postman, and is blocked in the browser console with an error naming a response header the server never set. The request genuinely succeeded — the browser is refusing to release the response to your page.

The fix is never on the client. JavaScript cannot grant itself permission, and there is no frontend setting that makes the browser accept a response it has already decided to block.

What is a CORS preflight request?

A preflight is an automatic OPTIONS request the browser sends before the real request, used to ask permission for a method or header that isn’t a simple request. The browser sends it when the actual call uses a non-simple Content-Type, a method other than GET/POST/HEAD, or a custom header such as Authorization.

The server must answer the OPTIONS request with its own CORS headers. This is where most “I added the headers and it still fails” cases come from: the real POST carries correct headers, but the preflight that preceded it returned a 404 or a body with no CORS headers at all, so the browser cancelled before the real request was ever sent.

A correct preflight response looks like this:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400

How do I fix a CORS error?

Fix the server, and fix it in this order.

1. Add CORS middleware to the API. Every major framework ships it — Express uses the cors package, FastAPI uses CORSMiddleware, Django uses django-cors-headers, Flask uses Flask-CORS. Configure it in one place at app startup rather than decorating individual routes.

2. Allowlist the exact origins. List your frontend origins explicitly, and keep the environment’s development ports separate from production:

import cors from "cors";

const allowedOrigins = [
  "http://localhost:5173",
  "https://app.example.com",
];

app.use(cors({
  origin: allowedOrigins,
  methods: ["GET", "POST", "PUT", "DELETE"],
  allowedHeaders: ["Content-Type", "Authorization"],
  credentials: true,
}));

3. Confirm the headers are on error responses. If an error handler or proxy strips headers, every failure looks like a CORS failure. Check the response in the browser’s Network tab, not the Console tab, and look at the actual status code.

4. Never disable the browser check. The --disable-web-security flag and similar workarounds remove a real protection and only affect the machine you run them on — so the bug reappears for every user, and in every other browser. Configure the server instead.

Where AI coding assistants get CORS wrong

  • Wildcard origin with credentials. origin: "*" combined with credentials: true is rejected by browsers, and “fixing” it by reflecting the request’s Origin header back turns CORS into a no-op for any attacker-controlled site.
  • Allowing every localhost port in production. origin: true or a permissive regex is common in generated code and should never ship.
  • Configuring CORS on the frontend. Middleware added to the React or Vue dev server config does not affect the API’s responses, which is where the browser looks.
  • Missing preflight handling. OPTIONS requests are often rejected by auth middleware before the CORS layer runs, so the preflight fails and the real request never happens.
  • Trusting Access-Control-Allow-Origin as authentication. CORS controls whether a browser releases a response. It is not an access control — anyone can call your API with curl. Authorization is a separate layer, covered in How to Design Authorization for Your App.
  • Assuming the error is a CORS bug when it is not. A 401 or 500 response with no CORS headers reports as a CORS error. Always read the real status code first.

Checklist

  • Configure CORS in one place on the API server using your framework’s maintained middleware.
  • Allowlist exact origins; keep development ports out of the production configuration.
  • Handle OPTIONS preflight requests, including in your auth and rate-limit layers.
  • Set Access-Control-Allow-Headers to include every custom header the client sends.
  • Only set credentials: true when the frontend actually authenticates with cookies, and never combine it with a wildcard origin.
  • Confirm headers survive error responses and any reverse proxy in front of the API.
  • Read the real status code from the Network tab before assuming CORS is the cause.
  • Add a Content-Security-Policy so response headers are already part of your security posture — see What Is a Content Security Policy (CSP)?.
  • Remember that a browser API key is not a secret, whatever CORS is set to — see Why Your Frontend API Keys Are Not Secret.

FAQ

What is CORS in simple terms?

Cross-Origin Resource Sharing is a browser security rule that stops your frontend JavaScript from calling an API on a different domain unless that API explicitly opts in with response headers. The browser enforces it, not the server, which is why the same request works fine in Postman or curl and fails in the browser.

How do I fix a CORS error?

Add CORS headers to the API’s responses — most frameworks ship middleware for it. Configure it on the server, allow the specific origins your frontend actually uses, and send the headers even on error and preflight responses. Disabling the browser check with a command-line flag hides the problem instead of fixing it.

Why does CORS only fail in the browser?

Because the browser is the only party enforcing the same-origin policy. Tools like curl, Postman, and server-side code send requests without an Origin header and are not restricted, so a request that fails in the browser can succeed from your terminal. That difference is why CORS bugs look inconsistent during development.

Is CORS a security vulnerability?

CORS itself is not a vulnerability — it is a protection. The common mistake is misconfiguring it, most dangerously by reflecting any origin with credentials, which effectively disables the protection and lets any site make authenticated requests as a logged-in user.

Should I disable CORS to make it work?

No. Disabling the browser’s check hides the symptom and removes a real protection against cross-site request forgery. Fix the server configuration instead, and allow only the origins you control.

Does CORS stop other people from calling my API?

No. CORS only controls whether a browser hands a response to a page. Anyone can call your API directly with curl or a script, so your API still needs its own authentication and authorization — see What Is an API Gateway (and When Do You Need One)?.

Sources

Share: