DevLab
Text

CORS Explained: Why Your API Call is Blocked

Understand why browsers enforce the Same-Origin Policy, how CORS headers unlock cross-origin requests, and how to configure CORS correctly on your server.

What is the Same-Origin Policy?

Browsers enforce a rule: JavaScript on page A can only make network requests to the same origin (protocol + hostname + port). Without this policy, a malicious website could silently call your bank's API using your session cookies. CORS (Cross-Origin Resource Sharing) lets servers opt in to allowing specific cross-origin requests.

The CORS Flow

// Simple requests (GET/POST with basic headers):
Browser → GET https://api.example.com/data
          Origin: https://app.example.com

Server  → 200 OK
          Access-Control-Allow-Origin: https://app.example.com
// Browser sees the header → allows JS to read the response ✓

// Preflighted requests (DELETE, PUT, or custom headers):
Browser → OPTIONS https://api.example.com/data
          Access-Control-Request-Method: DELETE

Server  → 204 No Content
          Access-Control-Allow-Methods: GET, POST, DELETE
          Access-Control-Max-Age: 86400  // cache preflight 24h
// Then the actual DELETE is sent

Server Configuration

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

// Manual headers (any server)
res.setHeader('Access-Control-Allow-Origin', 'https://app.example.com');
if (req.method === 'OPTIONS') { res.status(204).end(); return; }

The Wildcard + Credentials Trap

// Works for public APIs (no cookies)
Access-Control-Allow-Origin: *

// REJECTED by browsers — wildcard + credentials is invalid:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

// Correct — must specify exact origin when using credentials:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

CORS is Browser-Only

CORS restrictions only apply to browser-based JavaScript. Server-to-server requests (curl, Node.js fetch, Postman) are never blocked by CORS. If an API call works in Postman but fails in the browser, it is a CORS configuration issue on the server — not a network or authentication problem.

Frequently Asked Questions

Why does my API call work in Postman but fail in the browser?

Postman is not a browser and does not enforce the Same-Origin Policy or CORS. Browsers block cross-origin requests unless the server sends the correct Access-Control-Allow-Origin header. The fix is always on the server side — add the appropriate CORS headers for your frontend's origin.

What is a CORS preflight request?

A preflight is an automatic OPTIONS request the browser sends before certain cross-origin requests — specifically requests using methods other than GET/POST/HEAD, or requests with custom headers like Authorization. The server must respond to the OPTIONS request with the allowed methods and headers. You can cache preflight results using the Access-Control-Max-Age header to reduce round trips.

Can I use Access-Control-Allow-Origin: * with cookies?

No. Browsers reject the combination of a wildcard origin (*) and Access-Control-Allow-Credentials: true. When you need to send cookies or authentication headers cross-origin, you must specify the exact origin (e.g., https://app.example.com) instead of using a wildcard.

How do I allow multiple origins in CORS?

The Access-Control-Allow-Origin header only accepts a single value — either one origin or *. To allow multiple specific origins, your server must read the incoming Origin header, check it against a whitelist, and dynamically set Access-Control-Allow-Origin to the matched origin. Most CORS libraries (like the Express cors middleware) handle this automatically when you pass an array of origins.

Does CORS protect my API from unauthorized access?

No. CORS is a browser security mechanism, not an API security mechanism. Any non-browser client (curl, server-side code, mobile apps) can call your API regardless of CORS settings. CORS prevents malicious websites from making requests using a visitor's browser session. You still need authentication (API keys, OAuth, JWTs) to secure your API endpoints.

More Learning Topics

RegexRegex Basics: A Complete Beginner's GuideRegexRegex Special Characters: Complete ReferenceRegexRegex Groups and Captures ExplainedRegexRegex Quantifiers: Complete GuideCSSCSS Selectors: The Complete GuideCSSCSS Specificity: Why Your Styles Aren't ApplyingJSONJSONPath Syntax: Query JSON Like XPathTimeUnix Timestamps ExplainedEncodingBase64 Encoding ExplainedEncodingJWT Structure and How It WorksEncodingJWT vs Session Tokens: Which Should You Use?EncodingJWT Refresh Tokens ExplainedCryptoHash Functions Explained: MD5, SHA-256, and When to Use EachEncodingURL Encoding Explained: What %20 Actually MeansJSONJSON Schema Explained: Validate Your JSON DataJSONJSON vs YAML: Which Should You Use?JSONJSON.stringify and JSON.parse: Edge Cases You Should KnowRegexRegex Lookahead and Lookbehind: Match Without ConsumingRegexRegex for Email Validation: The Right ApproachCSSThe CSS Box Model: margin, padding, border, and contentCSSFlexbox vs CSS Grid: When to Use EachCSSCSS Custom Properties (Variables) ExplainedTimeISO 8601 Explained: The Right Way to Format DatesTimeUnix Timestamps vs ISO 8601: Which to Use in Your API?EncodingUTF-8 Explained: How Computers Store TextTextHTTP Status Codes: A Practical Developer GuideRegexNamed Capture Groups in Regex: Clean ExtractionsColorsColor Spaces Explained: RGB, HSL, HEX, and BeyondColorsColor Contrast for Developers: WCAG Rules and How to CheckNumbersNumber Bases Explained: Binary, Octal, Decimal, and HexNumbersBitwise Operations for Web DevelopersHTMLHTML Semantic Elements: A Complete ReferenceTextText Encoding for Developers: ASCII, UTF-8, and UnicodeRegexWhat is Regex? Complete Guide for DevelopersJSONJSON Format Explained: Structure, Syntax, and Common ErrorsEncodingHow JWT Works: Header, Payload, Signature DecodedHTMLHow to Convert Any Website to Markdown (for LLMs, RAG & Docs)TextPreparing Website Content for RAG: Clean Markdown Pipelines