You've seen it: "Access to XMLHttpRequest at X from origin Y has been blocked by CORS policy." CORS errors are cryptic and frustrating, but they exist for good reason. Here's how to understand and fix them.

What Is CORS?

CORS (Cross-Origin Resource Sharing) is a security mechanism that controls which websites can access resources from another website. It prevents malicious scripts from stealing data.

Example Scenario

You're on bank.com (origin A). A malicious script tries to fetch your bank data from your-bank.com/api/accounts (origin B). CORS blocks this — the bank's API didn't give bank.com permission to access it.

Same-Origin vs Cross-Origin

Two URLs are same-origin if they share protocol, domain, and port:

https://example.com   (origin A)
https://example.com/page   ✓ Same origin
https://example.com:3000   ✗ Different port
http://example.com   ✗ Different protocol
https://example.co.uk   ✗ Different domain
https://api.example.com   ✗ Subdomain

How CORS Works

1. Preflight Request (OPTIONS)

Browser sends OPTIONS request to check if cross-origin request is allowed:

OPTIONS /api/data HTTP/1.1
Origin: https://myapp.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

2. Server Response

Server responds with CORS headers:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 3600

3. Actual Request

If allowed, browser sends the real request.

Common CORS Headers

From Server (Response Headers)

  • Access-Control-Allow-Origin: Which origins can access
  • Access-Control-Allow-Methods: Allowed HTTP methods
  • Access-Control-Allow-Headers: Allowed request headers
  • Access-Control-Max-Age: Cache preflight response (seconds)
  • Access-Control-Allow-Credentials: Allow cookies/auth

From Browser (Request Headers)

  • Origin: The origin making the request
  • Access-Control-Request-Method: Method the request will use
  • Access-Control-Request-Headers: Headers the request will include

Fixing CORS Errors

1. Allow Specific Origin

# Server-side (Express.js)
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'https://myapp.com');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

2. Allow All Origins (Development Only)

res.setHeader('Access-Control-Allow-Origin', '*');

⚠️ WARNING: Never use `*` in production. Any website can access your API.

3. Using Middleware

Node.js with CORS Package

const cors = require('cors');
const whitelist = ['https://myapp.com', 'https://example.com'];
app.use(cors({
  origin: whitelist,
  credentials: true
}));

Python/Flask

from flask_cors import CORS
CORS(app, resources={r"/api/*": {"origins": ["https://myapp.com"]}})

PHP

header('Access-Control-Allow-Origin: https://myapp.com');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

Testing CORS

Use our CORS Tester to validate cross-origin requests:

  1. Enter your API endpoint
  2. Specify origin to test from
  3. Select method and headers
  4. See if CORS allows it

Common CORS Mistakes

1. Allowing All Origins

`Access-Control-Allow-Origin: *` + credentials = security hole.

2. Forgetting to Allow Credentials

// Doesn't work: cookies aren't sent
fetch('https://api.example.com', {
  credentials: 'include'
});

Server needs:

Access-Control-Allow-Credentials: true

3. Not Handling Preflight (OPTIONS)

Server must respond to OPTIONS requests with 200. If it returns 404, CORS fails.

4. Wrong Origin Format

Use full URL: `https://example.com`, not `example.com` or `https://example.com/`

CORS Doesn't Exist in Real Browsers

CORS is a browser security feature. Server-to-server requests don't have CORS issues:

// Browser request - CORS applies
fetch('https://api.example.com/data');

// Server-to-server - CORS doesn't apply
curl https://api.example.com/data

Troubleshooting CORS in DevTools

  1. Open DevTools (F12)
  2. Go to Network tab
  3. Find the failed request
  4. Check Response Headers for `Access-Control-Allow-Origin`
  5. If missing, server needs to add it

Pro Tips

  • Whitelist specific origins, not `*`
  • Test CORS before deployment
  • Cache preflight responses (higher Max-Age)
  • Use HTTPS in production (required for credentials)
  • Monitor CORS errors in logs

Conclusion

CORS isn't a bug — it's security. Once you understand the handshake, fixing CORS errors is straightforward. Whitelist your trusted origins, allow the right headers, and test thoroughly. Your API will be both secure and accessible.