Updated April 2026

Blocked by CORS Policy

Access to fetch at 'https://api.example.com/data' from origin 'https://app.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check.

What this error means

The browser sent an OPTIONS preflight to your API and the response either returned non-CORS headers, the wrong Access-Control-Allow-Origin, or a non-2xx status. The actual request was never sent.

The most common causes

1. OPTIONS handler missing entirely

Your server doesn't handle OPTIONS at all — it returns 404 or 405. Browsers require 200 or 204 with CORS headers.

# Nginx — add OPTIONS handling BEFORE your location blocks
if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin "https://app.example.com"; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; return 204;
}

2. Wrong Access-Control-Allow-Origin value

The origin in the request doesn't match what the server returns. Common issue: trailing slash, www vs non-www, http vs https.

# Check what the browser sends in the request
Origin: https://app.example.com

# Your server must return EXACTLY this value (or *)
Access-Control-Allow-Origin: https://app.example.com

3. Missing Authorization in Access-Control-Allow-Headers

When your frontend sends an Authorization header, the preflight response must explicitly list it:

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

4. Framework swallowing OPTIONS before your handler

# Express — cors() middleware must come BEFORE your route handlers
const cors = require('cors');
app.use(cors({ origin: 'https://app.example.com' }));
app.options('*', cors()); // Handle preflight for all routes

Quick debug

Open DevTools → Network → find the OPTIONS request → check the response status and headers. The preflight must return 200 or 204 with matching CORS headers.

Test your live CORS preflight — CORSFixer →