REST API CORS
A developer builds a web page, calls an API from JavaScript, and sees a red error in the browser console about CORS. Almost every web developer meets this message. CORS stands for Cross-Origin Resource Sharing. It is a browser rule that decides when a page may read responses from a different website.
The Building Guard Picture
Imagine an office building with a guard at the front desk. A visitor from another company asks to enter. The guard checks a list that the building owner provided. Visitors on the list walk in, and everyone else waits outside. The browser plays the guard, and the API server owns the list.
What Is an Origin
An origin combines three parts: the scheme, the host, and the port.
https://shop.example.com:443 │ │ │ scheme host port
| Page Origin | API Origin | Same Origin |
|---|---|---|
| https://shop.example.com | https://shop.example.com | Yes |
| https://shop.example.com | https://api.example.com | No (different host) |
| https://shop.example.com | http://shop.example.com | No (different scheme) |
| http://localhost:3000 | http://localhost:8080 | No (different port) |
The browser blocks scripts from reading responses across origins unless the server grants permission.
Simple Requests
A simple GET request goes straight to the server. The browser adds an Origin header, and the server answers with an Access-Control-Allow-Origin header.
GET /products Origin: https://shop.example.com HTTP/1.1 200 OK Access-Control-Allow-Origin: https://shop.example.com
The browser compares the two origins. A match lets the script read the response. A missing or different value blocks it.
Preflight Requests
Requests that use methods such as PUT or DELETE, or headers such as Authorization, trigger a preflight. The browser sends an OPTIONS request first to ask permission.
Browser ── OPTIONS /orders/5
Origin: https://shop.example.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: authorization ──→ API Server
Browser ←── 204 No Content
Access-Control-Allow-Origin: https://shop.example.com
Access-Control-Allow-Methods: GET, DELETE
Access-Control-Allow-Headers: authorization
Access-Control-Max-Age: 600 ──────────────────── API Server
Browser ── DELETE /orders/5 ──→ API Server
The Max-Age value lets the browser remember the answer for 600 seconds and skip repeated preflights.
Key Response Headers
| Header | Purpose |
|---|---|
| Access-Control-Allow-Origin | Names the allowed origin |
| Access-Control-Allow-Methods | Lists allowed methods |
| Access-Control-Allow-Headers | Lists allowed request headers |
| Access-Control-Allow-Credentials | Allows cookies and auth data |
| Access-Control-Max-Age | Sets preflight cache time |
Configuration Advice
- Allow only the origins that need access, and keep the list short.
- Use the wildcard * only for fully public data with no credentials.
- Return the exact requesting origin from an allowlist when credentials are involved.
- Send a Vary: Origin header so caches store one copy per origin.
- Handle OPTIONS requests on every route that browsers call.
Credentials and Cookies
Browsers hide cookies from cross-origin requests by default. A page that needs cookies must set credentials: "include" in its fetch call, and the server must answer with Access-Control-Allow-Credentials: true and a specific origin value. Both sides must agree, or the browser drops the response.
Page script: fetch(url, { credentials: "include" })
Server reply: Access-Control-Allow-Origin: https://shop.example.com
Access-Control-Allow-Credentials: true
Reading the Console Error
The browser console names the failed check. A message about a missing Allow-Origin header means the server sent no CORS headers. A message about a preflight failure means the OPTIONS request returned an error status or lacked the right headers. Read the exact wording before changing any code, because each message points to a different fix.
What CORS Does Not Do
CORS protects users inside browsers. It does not protect the API. Tools such as cURL and Postman ignore CORS completely, and any attacker can send direct requests. Authentication, authorization, and validation remain the real defenses.
Common Mistakes
Wildcard with Credentials
Browsers reject Access-Control-Allow-Origin: * when the request includes cookies. Name the exact origin instead.
Fixing the Error in the Frontend
Front-end code cannot cure a CORS error. The API server must send the correct headers.
Blocked OPTIONS Requests
An authentication layer that demands a token on OPTIONS requests breaks every preflight. Let OPTIONS pass before authentication runs.
