What is CORS?

Cross-Origin Resource Sharing (CORS) is a browser security mechanism that restricts web pages from making requests to a domain different from the one that served the page. When your frontend (e.g., https://myapp.com) makes an API call to a different domain (e.g., https://api.example.com), the browser first checks whether the server explicitly allows it.

If the server doesn't include the proper Access-Control-Allow-Origin headers in its response, the browser blocks the request and throws a CORS error. Importantly, CORS is enforced by the browser — the request still reaches your server, but the browser prevents the JavaScript from reading the response.

Common CORS Errors

  • No 'Access-Control-Allow-Origin' header: The server response is missing the CORS header entirely. Fix: add the header to your server's response.
  • Preflight request doesn't pass: For requests with custom headers or non-simple methods (PUT, DELETE), browsers send an OPTIONS preflight request. Your server must respond correctly to this.
  • Credentials flag: When using cookies or Authorization headers with withCredentials: true, the server must return Access-Control-Allow-Credentials: true and the origin must be specific (not *).
  • Allowed headers mismatch: If your request includes a header not listed in Access-Control-Allow-Headers, the preflight fails.

How to Fix CORS Per Framework

Use the tool above to generate the exact fix for your backend. The general principle is the same across all frameworks: configure your server to return the appropriate Access-Control-Allow-* headers. For production, always specify the exact allowed origins rather than using a wildcard (*), especially when dealing with authenticated requests.

Understanding the CORS Preflight Mechanism

When a browser makes a cross-origin request that isn't "simple" (GET/POST with basic headers), it first sends an OPTIONS preflight request to ask the server for permission. This two-step process is the source of most CORS confusion.

What Triggers a Preflight Request

  • Custom Headers: Any header beyond Accept, Content-Type (with simple values), and Content-Language triggers a preflight. Common triggers: Authorization, X-Requested-With, X-API-Key
  • Non-Simple Methods: PUT, DELETE, PATCH all trigger preflights. GET and POST with form data do not.
  • Content-Type beyond simple values: application/json triggers a preflight, while application/x-www-form-urlencoded does not. This is why fetch with JSON body often fails when the same endpoint works with form data.

CORS Debugging Checklist

When you encounter a CORS error, work through this checklist in order:

  • 1. Check the browser console: The error message tells you exactly which header is missing or misconfigured
  • 2. Inspect the OPTIONS response: Open DevTools → Network tab → filter by the failed request → check if the OPTIONS response includes the correct Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers
  • 3. Verify the origin matches exactly: http://localhost:3000 and http://localhost:3001 are different origins. Trailing slashes matter too.
  • 4. Check credentials mode: If you're sending cookies, the server must respond with Access-Control-Allow-Credentials: true AND cannot use wildcard (*) for Allow-Origin
  • 5. Verify your proxy isn't stripping headers: Reverse proxies (Nginx, Cloudflare, AWS ALB) sometimes strip or override CORS headers

Common CORS Mistakes in Production

The most frequent production CORS issues include: using Access-Control-Allow-Origin: * with credentials (this silently fails), forgetting to handle OPTIONS requests in serverless functions (Lambda, Vercel), and not including Vary: Origin when dynamically setting the Allow-Origin header (causing CDN caching issues). Another common mistake is fixing CORS in development but deploying with a different proxy configuration that strips the headers.

Frequently Asked Questions about CORS

What causes a CORS error?

A CORS error occurs when a browser blocks a cross-origin request because the server response is missing the Access-Control-Allow-Origin header. The browser enforces the Same-Origin Policy — any request from a different domain, port, or protocol triggers a CORS preflight check. Importantly, CORS is enforced by the browser only; the request still reaches your server, but the browser prevents the JavaScript from reading the response.

How do I fix CORS in Express.js?

Install the cors package (npm install cors) and add app.use(cors()) to allow all origins, or specify exact origins: app.use(cors({ origin: 'https://yourdomain.com' })). For requests with cookies or Authorization headers, set credentials: true and never use a wildcard (*) as the allowed origin — you must specify the exact domain.

What is a CORS preflight request?

A preflight is an HTTP OPTIONS request the browser sends automatically before cross-origin requests that use custom headers or non-simple HTTP methods (PUT, DELETE, PATCH). The server must respond to OPTIONS with Access-Control-Allow-Methods and Access-Control-Allow-Headers headers, plus a 200 or 204 status. If the preflight fails, the actual request is never sent.

Why does CORS work in Postman but not in the browser?

CORS is a browser security mechanism — it does not apply to server-to-server communication or tools like Postman, curl, or REST clients. Postman sends requests directly without enforcing same-origin policy, so the request succeeds. In the browser, JavaScript is restricted from reading cross-origin responses unless the server explicitly allows it via CORS headers.

Related Developer Tools