DeveloperSecurity

What Is CORS and How to Fix It

CORS explained: same-origin policy, preflight requests, headers, and how to fix cross-origin errors.

What Is CORS?

CORS (Cross-Origin Resource Sharing) is a browser mechanism that allows web pages to access resources from different domains/origins securely.

Without CORS, browser enforces same-origin policy: scripts from example.com cannot access API from api.example.com. CORS relaxes this restriction when properly configured.

Same-Origin Policy

Same origin = protocol + domain + port must match exactly.

https://example.comhttps://example.com/api ✓ Same origin
https://example.comhttps://api.example.com ✗ Different subdomain
https://example.comhttp://example.com ✗ Different protocol
https://example.com:3000https://example.com:3001 ✗ Different port

How CORS Works

1

Browser sends preflight request

OPTIONS request with origin header

2

Server responds with CORS headers

Access-Control-Allow-Origin, Access-Control-Allow-Methods

3

Browser checks response

Verifies requesting origin is allowed

4

Browser sends actual request

Only if preflight succeeds

Common CORS Headers

Access-Control-Allow-Origin

* or https://example.com

Access-Control-Allow-Methods

GET, POST, PUT, DELETE

Access-Control-Allow-Headers

Content-Type, Authorization

Access-Control-Allow-Credentials

true (allow cookies)

CORS Headers Detailed Explanation

Access-Control-Allow-Origin

Specifies which origins can access the resource. Use '*' for public APIs. Use specific domain for sensitive operations. Can only have one value or '*'.

Access-Control-Allow-Methods

HTTP methods allowed on the resource. If omitted, browser assumes only GET and HEAD. Example: GET, POST, PUT, DELETE, PATCH.

Access-Control-Allow-Headers

Request headers the browser can send. Must include custom headers like Authorization, X-API-Key. Usually includes Content-Type, Accept.

Access-Control-Allow-Credentials

Allow credentials (cookies, auth headers) in cross-origin requests. Only works with specific origin, not '*'. Client must also set credentials: 'include'.

Access-Control-Max-Age

Seconds browser can cache preflight response. Reduces preflight requests. Example: 3600 = 1 hour. Be careful with long values when API changes frequently.

Access-Control-Expose-Headers

Which response headers are exposed to browser. By default, only CORS-safe headers exposed. Example: X-Total-Count, X-Page-Number.

Common CORS Errors and Solutions

No 'Access-Control-Allow-Origin' header

Backend must send CORS headers. Configure your server/framework to include Access-Control-Allow-Origin header in responses. Add middleware or configuration.

Credentials are included but origin is '*'

Cannot use '*' with credentials. Specify exact origin (e.g., https://example.com) and set Access-Control-Allow-Credentials: true.

Authorization header blocked

Authorization not in default safe headers. Server must include Authorization in Access-Control-Allow-Headers header.

Preflight request failed

Preflight (OPTIONS) returned error code. Check if OPTIONS method is allowed. Verify preflight responds with correct CORS headers.

Custom headers being blocked

Custom headers need explicit Access-Control-Allow-Headers. Add custom headers like X-API-Key or X-Request-ID to the list.

CORS Configuration Examples

Node.js/Express

const cors = require('cors');

// Allow all origins
app.use(cors());

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

Python/Flask

from flask_cors import CORS, cross_origin

# Allow all origins
CORS(app)

# Allow specific origin
CORS(app, resources={
  r"/api/*": {
    "origins": "https://example.com",
    "methods": ["GET", "POST", "PUT", "DELETE"],
    "allow_headers": ["Content-Type", "Authorization"]
  }
})

CORS Preflight Request Deep Dive

What triggers a preflight? Browser automatically sends preflight for:

  • • HTTP methods other than GET, HEAD, POST
  • • Custom headers (Authorization, X-API-Key, etc.)
  • • Content-Type other than form-urlencoded, form-data, text/plain
  • • Credentials in requests (cookies, auth)

Preflight Flow: Browser sends OPTIONS request → Server responds with CORS headers → Browser checks if allowed → Only then sends actual request.

Example Preflight Request Headers:

OPTIONS /api/data HTTP/1.1

Origin: https://example.com

Access-Control-Request-Method: POST

Access-Control-Request-Headers: Authorization, Content-Type

CORS Security Best Practices

Never use '*' with credentials

Always specify exact origin when allowing credentials. Wildcard + credentials is not allowed by browsers.

Validate origin on backend

Don't just trust the Origin header. Validate it against allowed list. Origin can be forged by attackers.

Limit exposed headers

Only expose headers clients actually need. Don't expose sensitive internal headers.

Use credentials: 'include' carefully

Sending credentials cross-origin exposes cookies to attacks. Only use when necessary and with trusted origins.

Set appropriate Max-Age

Don't cache preflight responses too long (max 1 hour recommended) as API endpoints may change.

Whitelist origins explicitly

Don't allow all origins unless API is public and has no authentication. Use specific domain list.

Audit CORS configuration

Regularly review CORS settings. Overly permissive CORS can expose APIs to unauthorized access.

CORS FAQ

Is CORS a server-side or client-side issue?

CORS is enforced by the browser. Server sends CORS headers to tell browser if request is allowed. It's not a server blocking request, but browser blocking response.

Can I bypass CORS with a proxy?

Yes, same-origin proxy works because browser only sees requests to same origin. But this is a workaround, not a solution. Fix CORS on the actual API.

Why does the browser block CORS requests?

Security: Prevents malicious websites from stealing data from other sites without permission. Protects users' sensitive information (bank data, emails, etc).

Do API calls from backend (server-to-server) need CORS?

No. CORS only applies to browser requests. Server-to-server calls bypass CORS because servers don't enforce same-origin policy.

How do I test CORS locally?

Start dev server on different ports (localhost:3000 frontend, localhost:8000 API). Browser treats different ports as different origins.

Related Concepts

Related Tools

HTTP Status Codes Guide

Understand CORS error responses.

Open Tool ?

OAuth 2.0 Guide

Authentication in cross-origin API calls.

Open Tool ?