Understanding CORS: Cross-Origin Resource Sharing
In the modern web, applications are rarely self-contained. Frontends and backends are often hosted on different domains, subdomains, or ports. This separation introduces a security feature called CORS (Cross-Origin Resource Sharing).
What Is CORS?
CORS is a browser security mechanism that controls how web pages can make requests to a different domain than the one that served the web page. It is a protocol implemented in browsers, not on the server itself.
Example:
Your app is hosted at https://frontend.com, and it wants to fetch data from https://api.backend.com.
By default, the browser blocks this request due to the same-origin policy — a rule that allows scripts running on one origin to access resources on the same origin only.
What Is the Same-Origin Policy?
The same-origin policy allows a webpage to make requests only to the same domain, protocol, and port it came from. This protects the user from malicious cross-site requests.
So:
- ✅ https://example.com/api → https://example.com/data
- ❌ https://example.com/api → https://anotherdomain.com/data
This is where CORS comes in — it relaxes the same-origin policy under controlled circumstances.
How CORS Works
When a frontend makes a request to a different origin, the browser sends an extra HTTP request called a preflight request (for some types of calls like POST, PUT, or custom headers). This request uses the OPTIONS method.
Example:
OPTIONS /data HTTP/1.1
Origin: https://frontend.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
The server must respond with:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
If the headers are missing or incorrect, the browser blocks the request.
Common CORS Response Headers
- Access-Control-Allow-Origin Specifies the origin allowed to access the resource. Example: Access-Control-Allow-Origin: * (public access) or a specific origin.
- Access-Control-Allow-Methods What HTTP methods are permitted (e.g., GET, POST, PUT, DELETE).
- Access-Control-Allow-Headers Which headers can be used in the actual request (e.g., Authorization, Content-Type).
- Access-Control-Allow-Credentials If true, allows credentials like cookies or HTTP authentication to be included.
Enabling CORS on the Server
Express.js (Node.js)
const cors = require('cors');
const express = require('express');
const app = express();
app.use(cors({
origin: 'https://frontend.com',
credentials: true
}));
Ruby on Rails
# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'https://frontend.com'
resource '*', headers: :any, methods: [:get, :post, :options], credentials: true
end
end
CORS Is Not a Security Wall
CORS is not a server-side security measure. It only tells the browser how to behave. Malicious clients like Postman or curl can still send requests — it’s your server’s job to authenticate and authorize properly.
Common CORS Errors
- “No ‘Access-Control-Allow-Origin’ header is present” → Your server isn’t sending the right CORS headers.
- “CORS policy: Request header field is not allowed” → You used a custom header without adding it to Access-Control-Allow-Headers.
- Preflight request fails with 403 → Your server blocks the OPTIONS method.
Summary
- CORS enables secure cross-origin communication between browsers and servers.
- It relies on specific HTTP headers to permit or deny access.
- Always configure CORS deliberately — be careful with Access-Control-Allow-Origin: * and credentials.