Title
No "Access-Control-Allow-Origin" Header: Fixing the CORS Error for Real
Alternate Title Options
Meta Description (155-160 chars)
Fix the CORS error "No Access-Control-Allow-Origin header" with safe allowlists, correct preflight responses, credential handling, and fast debugging checks.
Assumptions
1) Hook: the scene + the pain
The demo starts in 15 minutes.
You open the app and every API call fails with a bright red CORS error.
You try a quick fix: set Access-Control-Allow-Origin to "".
Now the error is gone, but cookies stopped working and users are logged out.
Someone suggests a dev proxy hack to hide the error.
You know that will fail in production.
Here is what is actually happening and how to fix it.
2) The real problem (plain English)
CORS is a browser security rule, not a server feature. The browser decides whether to allow the response, and it requires the server to opt in with the right headers.
If the browser is making a cross-origin request, it may send a preflight OPTIONS request first. If the server does not answer that preflight correctly, the browser blocks the real request even if the API works in Postman.
Three things people say in the heat of this bug:
> If you only remember one thing: CORS is enforced by the browser, and the browser needs explicit permission for your exact origin and headers.
3) What is going on under the hood (deeper, but still clear)
The browser compares three pieces of data:
When the request is "non-simple" (custom headers, JSON content type, credentials, or non-GET methods), the browser sends a preflight OPTIONS request to ask the server if the real request is allowed. If that preflight is missing or wrong, the browser blocks the call.
A common trap is mixing wildcard origins with credentials. If you send cookies, you must return a specific origin, not "".
4) The fix (step-by-step)
Step 1: Identify the actual origin of your frontend.
Check the exact scheme, host, and port shown in the browser console.
Step 2: Confirm whether a preflight happens.
Open DevTools -> Network and look for OPTIONS before the failing request.
Step 3: Answer preflight correctly.
Return Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers.
Step 4: Handle credentials safely.
If you need cookies or auth headers, set Access-Control-Allow-Credentials to true and return a specific origin.
Step 5: Validate with curl.
Use a simple OPTIONS request to confirm your headers before testing the UI again.
Quick win
Best practice
> Pro tip: Start by fixing preflight. If OPTIONS fails, the browser never sends your real request.
> Watch out: Setting Access-Control-Allow-Origin to "" is not safe for credentialed requests and can leak data.
5) Example(s) (code/commands/config) + explanation line-by-line
Example A: Express CORS middleware with allowlist
const allowedOrigins = new Set([
'https://vic-e.com',
'https://admin.vic-e.com'
]);
app.use((req, res, next) => {
const origin = req.headers.origin;
if (origin && allowedOrigins.has(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Vary', 'Origin');
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
if (req.method === 'OPTIONS') {
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PATCH,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');
return res.status(204).end();
}
next();
});Explanation:
Validate:
curl -i -X OPTIONS https://api.vic-e.com/v1/profile -H "Origin: https://vic-e.com" -H "Access-Control-Request-Method: GET"Example B: Fetch with credentials (client side)
async function loadProfile() {
const response = await fetch('https://api.vic-e.com/v1/profile', {
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Request failed: ' + response.status);
}
return response.json();
}Explanation:
6) Common pitfalls (and how to spot them fast)
Debugging: symptoms -> likely causes -> checks
7) Checklist / TL;DR (copyable)
- [ ] Confirm the exact frontend origin (scheme + host + port).
- [ ] Check if OPTIONS preflight happens.
- [ ] Return Allow-Origin, Allow-Methods, Allow-Headers.
- [ ] If using cookies, return a specific origin and Allow-Credentials.
- [ ] Add Vary: Origin for safe caching.
- [ ] Validate with curl before retesting the UI.8) Optional: When NOT to do this + alternatives
If you do not control the API, you cannot change its CORS behavior. Use a backend proxy you control and keep CORS strict at that boundary.
If this is a public API, consider token-based auth instead of cookies to reduce credentialed CORS complexity.
9) Best practices
10) Closing: what to do next
Add a small CORS test to your pipeline that fails if preflight headers are missing. That prevents this from regressing the next time a new route ships.
Copy/paste checklist:
- [ ] Check origin, then preflight.
- [ ] Allowlist the exact origin.
- [ ] Handle OPTIONS with 204.
- [ ] Use Allow-Credentials only when needed.
- [ ] Verify headers with curl.Mini FAQ:
Q: Why does it work in Postman but fail in the browser?
A: Postman does not enforce CORS; browsers do.
Q: Can I just set Access-Control-Allow-Origin to "*"?
A: Not if you need cookies or auth headers. You must echo a specific origin.
Q: Why does the browser send OPTIONS before my request?
A: That is the preflight check for non-simple requests.
Q: Do I need CORS for same-origin requests?
A: No. Same origin requests do not require CORS headers.
Recommended Reading
💬Discussion
No comments yet
Be the first to share your thoughts!
