What is CORS? — Cross-Origin Resource Sharing Explained
Definition
CORS (Cross-Origin Resource Sharing) is a browser security mechanism that controls how web pages from one origin can request resources from a different origin. It works through a system of HTTP headers that tell the browser whether a cross-origin request should be allowed or blocked.
CORS is enforced by browsers, not by servers. When a web application makes a cross-origin HTTP request, the browser adds an Origin header and checks the server's response for CORS headers before allowing the frontend code to access the response.
Same-Origin Policy
The Same-Origin Policy (SOP) is the foundation that CORS is designed to relax. SOP blocks scripts from accessing resources from a different origin. Two URLs share the same origin if they have the same:
- Protocol (
httpvshttps) - Host (
api.example.comvsexample.com) - Port (
:443vs:8080)
| URL A | URL B | Same Origin? | Reason |
|---|---|---|---|
https://example.com/page1 |
https://example.com/page2 |
✅ Yes | Same protocol, host, port |
https://example.com |
https://api.example.com |
❌ No | Different host (subdomain) |
https://example.com |
http://example.com |
❌ No | Different protocol |
https://example.com |
https://example.com:8080 |
❌ No | Different port |
Without SOP, malicious sites could read sensitive data from other origins (e.g., bank accounts). CORS provides a safe, opt-in mechanism to bypass SOP when the server explicitly grants permission.
CORS Headers
CORS is governed by a set of HTTP response headers that the server sends to the browser:
| Header | Purpose | Example |
|---|---|---|
Access-Control-Allow-Origin |
Specifies which origins are allowed | https://example.com or * |
Access-Control-Allow-Methods |
Lists permitted HTTP methods | GET, POST, PUT, DELETE |
Access-Control-Allow-Headers |
Lists permitted request headers | Content-Type, Authorization |
Access-Control-Allow-Credentials |
Whether credentials (cookies, auth headers) are allowed | true |
Access-Control-Expose-Headers |
Which response headers the client can access | X-Custom-Header |
Access-Control-Max-Age |
How long the preflight result can be cached | 86400 (24 hours) |
Access-Control-Request-Method |
Used in preflight OPTIONS request | POST |
Access-Control-Request-Headers |
Used in preflight OPTIONS request | content-type, authorization |
Simple Requests vs Preflight Requests
Simple Requests
A cross-origin request is considered "simple" if it meets all of these conditions:
- Method is
GET,HEAD, orPOST - Only these headers are set:
Accept,Accept-Language,Content-Language,Content-Type(with valuesapplication/x-www-form-urlencoded,multipart/form-data, ortext/plain) - No event listeners on
XMLHttpRequestUpload - No
ReadableStreamused
For simple requests, the browser makes the request directly and checks the Access-Control-Allow-Origin header in the response.
Preflight Requests (OPTIONS)
For all other requests (e.g., custom headers like Authorization, methods other than GET/HEAD/POST, or Content-Type: application/json), the browser sends a preflight request using the HTTP OPTIONS method before the actual request:
OPTIONS /api/data HTTP/1.1
Host: api.example.com
Origin: https://myapp.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-typeIf the server responds with appropriate CORS headers, the browser proceeds with the actual request. If not, the browser blocks the request and throws a CORS error.
Handling Credentials
When a cross-origin request includes credentials (cookies, HTTP authentication, or TLS client certificates), special rules apply:
- The request must set
credentials: "include"(in fetch) orwithCredentials: true(in XMLHttpRequest) - The server must respond with
Access-Control-Allow-Credentials: true - The server must not use
Access-Control-Allow-Origin: *— it must specify an explicit origin - The server must not use
Access-Control-Allow-Headers: *— it must specify explicit headers
Common CORS Errors and Solutions
Error 1: "No 'Access-Control-Allow-Origin' header is present"
Cause: The server did not include the Access-Control-Allow-Origin header in its response.
Solution: Configure the server to include the header. For example, in Express.js:
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://myapp.com");
next();
});Error 2: "Method PUT is not allowed by Access-Control-Allow-Methods"
Cause: The server's Access-Control-Allow-Methods header does not include the HTTP method used in the request.
Solution: Add the method to the allowed list:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH
Error 3: "Request header field authorization is not allowed by Access-Control-Allow-Headers"
Cause: The request includes a custom header (e.g., Authorization) that the server hasn't whitelisted.
Solution: Add the header to Access-Control-Allow-Headers:
Access-Control-Allow-Headers: Content-Type, Authorization
Error 4: "The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*'"
Cause: Using * with credentials enabled or with a preflight response that doesn't match.
Solution: Return the specific origin from the request's Origin header instead of *.
Error 5: "Response to preflight request doesn't pass access control check"
Cause: The OPTIONS preflight response is missing CORS headers or has mismatched values.
Solution: Ensure your server handles OPTIONS requests and returns the correct CORS headers.
Debugging CORS with Browser Dev Tools
Chrome DevTools
- Open the Network tab (F12)
- Look for failed requests highlighted in red
- Click the failed request and view the Headers tab
- Under "Response Headers", check for CORS headers
- The Console tab shows CORS error messages with details
- Use the Issues tab for a summary of CORS problems
Firefox DevTools
- Open the Network tab (F12)
- Failed CORS requests show a cross-origin icon
- Click the request and inspect the Headers panel
- Firefox provides detailed CORS error messages in the Console
Common Debugging Steps
- Verify the
Originheader is being sent correctly - Check the server's response includes
Access-Control-Allow-Origin - Ensure preflight (OPTIONS) responses are correct
- Check for typo in origins (trailing slashes matter!)
- Verify CORS middleware is executed before other middleware
Server-Side Configuration Examples
Express.js (Node.js)
const cors = require("cors");
app.use(cors({ origin: "https://myapp.com" }));Nginx
add_header Access-Control-Allow-Origin "https://myapp.com";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";Apache (.htaccess)
Header set Access-Control-Allow-Origin "https://myapp.com"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"LangStop API & CORS Tools
- REST API Client — Test CORS headers and API endpoints
- URL Encoder — Encode URLs for API requests
- JWT Encoder — Create JWTs for authenticated cross-origin requests
- API Tools — Collection of API debugging utilities