A mechanism that allows restricted resources on a web page to be requested from another domain.
CORS (Cross-Origin Resource Sharing) is a security mechanism in web browsers that controls which websites can access resources from your web server. It prevents malicious websites from making unauthorized requests to your APIs on behalf of users.
Think of CORS as a security guard at a building entrance. The guard checks if visitors are on the approved list before letting them in. Similarly, CORS checks if a website is allowed to access your server before permitting the request.
The Security Problem: Without CORS, any website could send requests to any other site using your browser. Imagine visiting evil.com, which secretly sends requests to yourbank.com using your logged-in session cookies. It could transfer money without your knowledge.
Same-Origin Policy: Browsers enforce a "same-origin policy" - a webpage can only make requests to the same domain it came from. A page from example.com can only request data from example.com, not from api.example.com or other-site.com.
CORS Solution: CORS allows servers to explicitly grant permission for specific other domains to access their resources. Your API can say "I allow requests from app.example.com but not from evil.com."
An origin is the combination of:
These are different origins:
https://example.comhttp://example.com (different protocol)No related topics found.
https://api.example.com (different subdomain)https://example.com:3000 (different port)A request from one origin to another is "cross-origin" and subject to CORS.
Simple Requests:
https://app.example.com makes a request to https://api.example.comOrigin header: Origin: https://app.example.comAccess-Control-Allow-Origin: https://app.example.comIf the server does not send the correct headers, the browser blocks the response, and your JavaScript gets an error.
Preflight Requests: For complex requests (PUT, DELETE, custom headers), the browser sends a "preflight" OPTIONS request first:
Frontend Code:
// Running on https://app.example.com
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('CORS error:', error));
Backend Code (Express.js):
// Allow requests from app.example.com
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://app.example.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
Now the frontend can successfully fetch data from the API.
No CORS Headers: Server does not send any CORS headers. Browser blocks the response.
Access to fetch at 'https://api.example.com' from origin 'https://app.example.com' has been blocked by CORS policy
Wrong Origin: Server allows different origin than the requesting one.
The 'Access-Control-Allow-Origin' header has a value 'https://wrong.com' that is not equal to the supplied origin
Missing Preflight Headers: Server does not handle OPTIONS requests properly.
Response to preflight request does not pass access control check
Allow Specific Origin:
Access-Control-Allow-Origin: https://app.example.com
Allow Any Origin (development only, insecure for production):
Access-Control-Allow-Origin: *
Allow Credentials (cookies, authentication headers):
Access-Control-Allow-Credentials: true
Note: Cannot use * for origin when allowing credentials.
Allow Specific Methods:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Allow Custom Headers:
Access-Control-Allow-Headers: Content-Type, Authorization, X-Custom-Header
Cache Preflight:
Access-Control-Max-Age: 86400
Tells browser to cache preflight response for 24 hours, reducing preflight requests.
Separate Frontend and Backend:
https://app.mysite.com (React on Vercel)https://api.mysite.com (Node.js on AWS)Third-Party API Integration:
Microservices:
CORS and authentication are different:
CORS: Controls which domains can make requests Authentication: Controls which users can access resources
You need both. CORS prevents evil.com from accessing your API. Authentication prevents unauthorized users (even from allowed domains) from accessing protected data.
Development:
*) for convenienceProduction:
* with credentialsconst allowedOrigins = process.env.NODE_ENV === 'production'
? ['https://app.mysite.com']
: ['http://localhost:3000'];
JSONP: Old technique using script tags (not subject to same-origin policy). Insecure, deprecated.
Proxy Server: Route requests through your backend to bypass CORS. Adds latency, defeats security purpose.
Browser Extensions: Disable CORS in browser. Fine for local development, disables critical security in production.
The Right Solution: Configure CORS properly on your backend. It exists for security reasons.
Express (Node.js):
const cors = require('cors');
app.use(cors({
origin: 'https://app.example.com',
credentials: true
}));
Flask (Python):
from flask_cors import CORS
CORS(app, origins=['https://app.example.com'])
Django (Python):
# In settings.py
CORS_ALLOWED_ORIGINS = ['https://app.example.com']
These libraries handle all the headers and preflight requests automatically.
Check Browser Console: CORS errors appear in the browser console with specific messages about what went wrong.
Check Network Tab: Look at the failed request. See what headers were sent and received.
Verify Origin: Confirm your frontend origin matches what the backend allows. Even https vs http matters.
Test with cURL: Bypass the browser to test if the API works without CORS restrictions.
Use Browser DevTools: Some browsers have CORS debugging tools that show detailed information about blocked requests.
Native mobile apps (iOS, Android) do not have the same-origin policy. They are not browsers, so CORS does not apply. However, your API still needs authentication and authorization.
Web views within mobile apps do enforce CORS like regular browsers.
Too Restrictive: Your API only works from one specific domain. Makes development harder, reduces flexibility.
Too Permissive: Allowing * origin with credentials exposes your API to attacks from any website.
The Balance: Allow specific, trusted origins. Add origins as needed. Use environment variables to manage different origins for different environments.
"CORS is broken/annoying": CORS is security. It protects users. The "annoyance" is proper security requiring configuration.
"CORS blocks requests": Browsers block responses, not requests. The request reaches your server. The browser blocks your JavaScript from reading the response.
"Disabling CORS solves problems": It creates security vulnerabilities. The problem is misconfiguration, not CORS itself.
CORS is a critical security mechanism that every web developer must understand. It controls which websites can access your APIs, protecting users from malicious sites making unauthorized requests.
Proper CORS configuration requires understanding origins, configuring appropriate headers, and handling preflight requests. While it can be frustrating during development, it exists to keep users safe. Configure it correctly, and it works invisibly in the background, enabling secure cross-origin communication.