8 min readTechnical Guide

The Complete Guide to CORS in 2026: Everything Developers Need to Know

DC
DevConsole Team
Engineering @ DevConsole
The Complete Guide to CORS in 2026: Everything Developers Need to Know

The Complete Guide to CORS in 2026

CORS. Four letters that strike fear into the hearts of junior and senior developers alike. You're building a feature, everything works locally, you push to production, and suddenly—red console errors everywhere.

This guide covers everything: what CORS actually is, why it exists, how to configure it correctly, common pitfalls, and how to debug it without losing your mind.

What Is CORS?

CORS (Cross-Origin Resource Sharing) is a security mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.

It's essentially a gatekeeper. By default, browsers block web pages from making requests to a different domain than the one that served the web page. This is the Same-Origin Policy. CORS is the "exception" mechanism to let safe requests through.

The Golden Rule: CORS is verified by the browser, not the server. The server sends headers, but the browser decides whether to block the response.

Diagram showing browser blocking a cross-origin request Figure 1: The browser acts as the gatekeeper for cross-origin requests.

Why CORS Matters for Developers

Security

Without CORS, malicious sites could make requests to your internal APIs on behalf of logged-in users (CSRF attacks). CORS prevents unauthorized domains from accessing your data.

Mobile & SPAs

Modern web development often involves a frontend (e.g., React on vercel.app) talking to a backend (e.g., Node on railway.app). These are different origins. You need CORS to make this architecture work.

Public APIs

If you're building a public API, you need to explicitly allow everyone (or specific partners) to access it.

Required Headers in 2026

To enable CORS, your server needs to send specific HTTP headers.

The Big One: Access-Control-Allow-Origin

This header tells the browser which domains are allowed.

  • Wildcard: Access-Control-Allow-Origin: *
    Allows everyone. Good for public APIs (weather data, fonts). Bad for private user data.
  • Specific Domain: Access-Control-Allow-Origin: https://my-app.com
    Secure. Only the specified domain can read the response.

Handling Methods & Headers

  • Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
    Specifies which HTTP methods are allowed.
  • Access-Control-Allow-Headers: Content-Type, Authorization
    Lists headers the client is allowed to send (e.g., auth tokens).

Pro tip: Use DevConsole to inspect your API responses and verify these headers are being sent correctly.

The "Preflight" Request (OPTIONS)

Ever see an OPTIONS request in your network tab that you didn't send? That's a Preflight.

When does it happen?

Browsers send a preflight request before the actual request if:

  1. Function is not GET, HEAD, or POST.
  2. Custom headers are sent (e.g., Authorization, X-Custom-Header).
  3. Content-Type is strictly application/json (yes, really).

How it works

  1. Browser: "Hey Server, I'm planning to send a POST request with an Authorization header from my-app.com. Is that cool?" (This is the OPTIONS request)
  2. Server: "Yeah, my-app.com is on the list. You can use POST and Authorization." (Sends 200 OK with CORS headers)
  3. Browser: "Great, here's the actual POST request."

If the preflight fails (404, 500, or missing headers), the actual request is never sent.

Sequence diagram of OPTIONS preflight followed by POST request Figure 2: The "Preflight Dance" - Browser asks for permission before sending data.

10 Common CORS Mistakes (And How to Fix Them)

1. Missing OPTIONS Handler

Mistake: Your API handles GET and POST but 404s on OPTIONS.
Fix: Ensure your router or server is configured to respond to OPTIONS requests with a 200 status and CORS headers.
Why: Preflights fail, blocking the main request.

2. Double Wildcards

Mistake: Access-Control-Allow-Origin: https://a.com, https://b.com
Fix: You can only send one value or *. If you need multiple, you must check the request Origin header and dynamically reflect it if it matches your whitelist.
Why: The spec doesn't support comma-separated lists for this header.

3. Wildcards with Credentials

Mistake: Access-Control-Allow-Origin: * AND Access-Control-Allow-Credentials: true
Fix: If using credentials (cookies/auth headers), you MUST specify an exact origin.
Why: Security limitation to prevent unrestricted credentialed access.

4. Forgetting "Vary: Origin"

Mistake: Caching CORS responses without telling the browser/CDN to vary by Origin.
Fix: Add Vary: Origin header.
Why: Prevents a response meant for site-a.com from being served from cache to site-b.com.

5. Ignoring Localhost

Mistake: CORS policy blocks localhost:3000 during development.
Fix: Add localhost to your allowed origins in development environments.
Why: It's annoying to disable security just to code.

6. Misconfigured Cloud/Proxy

Mistake: Your Node app handles CORS, but Nginx or AWS API Gateway strips the headers.
Fix: Check every layer of your stack (Load Balancer -> Proxy -> App).
Why: Infrastructure can override application headers.

7. Protocol Mismatch

Mistake: Allowing http://my-app.com but accessing from https://my-app.com.
Fix: Schemes must match exactly.
Why: HTTP and HTTPS are different origins.

8. The "Simple Request" Trap

Mistake: Thinking you don't need CORS for POST requests.
Fix: Remember that application/json triggers a preflight.
Why: Only application/x-www-form-urlencoded, multipart/form-data, and text/plain are "simple".

9. Opaque Responses

Mistake: Making a no-cors request to an external API and trying to read the response.
Fix: You cannot read no-cors responses in JS. The server MUST enable CORS.
Why: no-cors is mostly for write-only requests (like analytics logging).

10. Local Files

Mistake: Testing file:///C:/Users/index.html.
Fix: Always run a local server (npx serve, python -m http.server).
Why: Browsers block local file requests for security.

Debugging CORS Issues with DevConsole

Stubborn CORS errors? DevConsole helps you see what's actually happening:

Check the Preflight

  1. Open DevConsole Network tab.
  2. Find the OPTIONS request.
  3. Check if it returned 200 OK.
  4. Verify Access-Control-Allow-Origin matches your current domain.

Compare Headers

DevConsole highlights missing or mismatched headers.

  • Request Origin: https://my-app.com
  • Response Allowed: https://other-app.com -> MISMATCH

Modify & Replay

Use DevConsole's API client to manually send OPTIONS requests to your server to test config without reloading your frontend app.

[!TIP] Deep Dive: Want to see exactly how network waterfralls affect your app performance? Check out our guide on Debug Network Waterfalls with API Toolkit.

Server-Side Config Examples

Node.js (Express)

const cors = require('cors');
app.use(cors({
  origin: 'https://my-app.com',
  methods: ['GET', 'POST'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

Next.js (next.config.js)

module.exports = {
  async headers() {
    return [
      {
        source: "/api/:path*",
        headers: [
          { key: "Access-Control-Allow-Credentials", value: "true" },
          { key: "Access-Control-Allow-Origin", value: "*" },
          { key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
        ]
      }
    ]
  }
}

Go (Gin)

router.Use(cors.New(cors.Config{
  AllowOrigins:     []string{"https://foo.com"},
  AllowMethods:     []string{"PUT", "PATCH"},
  AllowHeaders:     []string{"Origin"},
  ExposeHeaders:    []string{"Content-Length"},
  AllowCredentials: true,
}))

CORS Best Practices Checklist

Before going live:

  • [✓] Allowed specific origins (avoid * unless public API)

  • [✓] Handled OPTIONS (preflight) requests properly

  • [✓] Listed only necessary methods (e.g., typically don't need TRACE)

  • [✓] Whitelisted custom headers (Authorization, x-api-key)

  • [✓] Added Vary: Origin for caching

  • [✓] Tested with Access-Control-Allow-Credentials if using cookies

  • [✓] Verified error responses also send CORS headers (so frontend can read the error message)

  • [✓] Tested from a staging environment (different domain)

  • [✓] Tested from a staging environment (different domain)

Frequently Asked Questions (FAQ)

Q: Why does it work in Postman/Curl but fail in my browser?

A: Postman and Curl are not browsers. They do not enforce the Same-Origin Policy. CORS is strictly a browser security feature. A working Curl request only proves the server is reachable, not that it allows cross-origin browser requests.

Q: Can I just disable CORS?

A: For local development, you can use browser extensions, but do NOT rely on this. You must fix the server configuration for your actual users.

Q: Is Access-Control-Allow-Origin: * secure?

A: Only for truly public data (like a weather API). Never use it if your API returns private user data or requires authentication cookies.

Q: Why is my authorization header being blocked?

A: You likely forgot to add Authorization to the Access-Control-Allow-Headers list. The browser blocks any custom header not explicitly whitelisted.

Conclusion

CORS is a pain, but a necessary one. It keeps the web secure. Once you understand the "Preflight Dance" and strict header rules, debugging becomes much easier.

Don't let red console text ruin your day. Use DevConsole to inspect headers, simulate requests, and fix CORS policies in record time.

Have questions? Dealing with a weird CORS edge case? Drop a comment below or check out our API debugging tools.


Struggling with API headers? Try DevConsole - the developer toolkit that makes inspecting and debugging network requests painless.