Corporate Software
How to fix a CORS error: a step-by-step guide

Short answer
A CORS error means the browser is refusing to let your JavaScript code read the response to a request made to a different origin, because the server hasn’t explicitly allowed it. It isn’t a broken connection; it’s the browser’s same-origin security policy doing exactly what it’s designed to do.
The fix almost always belongs on the backend serving the API, not the frontend: returning the correct Access-Control-Allow-Origin header.
Why a CORS error happens
By default, browsers let JavaScript on a page send a request to a different origin (a different scheme, domain, or port), but they won’t let that code read the response. This rule is the same-origin policy. CORS (Cross-Origin Resource Sharing) is the mechanism that lets a server say “I’m allowing requests from this origin to read my response.” If the server doesn’t grant that permission through specific HTTP headers, the browser doesn’t block the request itself; it hides the response from your code and prints a CORS error to the console instead.
That distinction matters in practice: the request usually reaches the server, and the server usually does produce a response. The problem isn’t in the network layer, it’s the browser refusing to hand you that response. This is why most developers’ first instinct on seeing a CORS error is “my server is broken,” when the real cause is almost always a missing or misconfigured CORS header. Changing your fetch or axios call on the frontend won’t fix this as long as your code is hosted on a different origin than the API.
CORS errors show up especially often in a few recurring scenarios: a frontend running on localhost:3000 calling an API on localhost:8000 or a different domain; a mobile app’s web view calling an API hosted on a separate domain; or a WordPress site serving data to a headless frontend (Next.js, React) through its REST API. Even a different port counts as a different origin to the browser, and so does http://site.com versus https://site.com.
Typical messages you’ll see in the browser console
| Message | Typical cause | First fix |
|---|---|---|
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource |
The server isn’t returning any CORS header at all | Add the correct Access-Control-Allow-Origin header on the backend |
Response to preflight request doesn't pass access control check |
The OPTIONS (preflight) request isn’t being answered correctly | Make the server respond to OPTIONS with 200/204 and the right headers |
...must not be the wildcard '*' when the request's credentials mode is 'include' |
A wildcard origin is combined with credentials: 'include' |
Return the exact requesting origin instead of a wildcard |
No 'Access-Control-Allow-Headers' header is present |
The request carries a custom header (e.g. Authorization) the server doesn’t allow |
Add that header to the Access-Control-Allow-Headers list |
net::ERR_FAILED (no CORS message at all) |
The request never actually reached the server (DNS, SSL, wrong port) | Confirm this isn’t a connection error before assuming it’s CORS |
How to fix a CORS error, step by step
1. Confirm it’s actually a CORS error
Open your browser’s developer tools, go to the Network tab, and inspect the request. If it shows up red with no status code at all (e.g. (failed)), the problem is most likely not CORS; it’s probably DNS, an SSL certificate, or a wrong address or port. If the request clearly reached the server and got a response, but the console shows a red message mentioning CORS, your problem is genuinely a CORS configuration issue, and the fix belongs on the server side.
2. Add the correct Access-Control-Allow-Origin header on the backend
For a Node.js/Express API, the simplest fix is adding the cors package:
const cors = require('cors');
app.use(cors({ origin: 'https://yoursite.com' }));
If you’re using a reverse proxy like Nginx, you can add the header at that layer too:
add_header 'Access-Control-Allow-Origin' 'https://yoursite.com' always;
In production, scoping the origin to your real domain instead of * matters both for security and because requests carrying credentials won’t work with a wildcard at all.
3. Answer the preflight (OPTIONS) request correctly
Requests using PUT, DELETE, custom headers, or a application/json body count as “non-simple” requests, and the browser automatically sends an OPTIONS request before the real one. Your server needs to answer that OPTIONS request with Access-Control-Allow-Methods and Access-Control-Allow-Headers, usually with a 200 or 204 status; otherwise the browser never sends the actual request and just prints a preflight error. This step is the most common reason an API tests fine in Postman but fails in the browser, since Postman never sends a preflight request in the first place.
4. Avoid wildcards if you’re using credentials
If your request uses credentials: 'include' (a cookie-based session, an HttpOnly cookie, and similar), the browser rejects a server response that returns * as Access-Control-Allow-Origin. The header needs to contain the exact requesting origin, and the server also needs to add Access-Control-Allow-Credentials: true. Forgetting either of these two together is the most common CORS error on session-based APIs.
A fast workaround for local development: use a proxy
If you can’t change the backend during local development, or it isn’t ready yet, setting up a development proxy on the frontend is a practical stopgap. Vite’s server.proxy setting and webpack’s devServer.proxy setting both make browser requests look like they’re going to your own origin while forwarding them to the real API behind the scenes, so the browser never runs a CORS check on them. This fix is strictly for development; in production, the real solution is always configuring the correct CORS headers on the server itself.
CORS errors in WordPress and headless projects
When a WordPress site serves data through its REST API to a separate headless frontend (Next.js, React, a mobile app), WordPress core doesn’t grant CORS access to every origin by default. The fix is usually hooking into rest_api_init in your theme’s functions.php or a small plugin and adding the Access-Control-Allow-Origin header manually to the relevant requests; on some hosting setups, adding that same header through .htaccess or the server configuration is more reliable. We cover a different class of WordPress server-side failure in our guide to the WordPress database connection error. Unlike that one, a CORS error happens while the server is fully up and working; it’s a permissions question, not an outage.
What not to do, for security’s sake
Some developers facing a CORS error, without actually diagnosing it, reach for Access-Control-Allow-Origin: * on every route or install a browser extension that disables CORS checks locally. The first option can turn into a real security gap on any API that requires authentication or returns sensitive data, since your API loses any control over which sites can call it. The second only hides the error in your own browser; real users still hit it in theirs, so it should never be treated as an actual fix in production.
Common mistakes
The most common mistake is trying to fix the frontend code without reading the error first: CORS headers belong on the server, not the client. The second is carrying a temporary development proxy, or a browser extension workaround, into production. The third is trying a wildcard origin on an API that uses credentials; that combination is rejected outright by the browser and will never work. Finally, adding a CORS header only to the real request while forgetting the preflight response leaves the problem half-solved.
Checklist
- Did you confirm in the Network tab that the request actually reached the server?
- Did you read exactly which header the console message is complaining about: origin, headers, or credentials?
- Does your backend return
Access-Control-Allow-Originwith the correct origin value? - For non-simple requests, does the OPTIONS response include the right methods and headers?
- If you’re using credentials, are you returning an explicit origin plus
Access-Control-Allow-Credentials: trueinstead of a wildcard?
Next step
A CORS error is a sign the browser is doing its job protecting users, and it’s usually resolved in minutes once you add the right headers in the right place. The key is looking for the fix on the backend, not the frontend. If your company needs to build out API integrations, headless architectures, or reliable data exchange between existing systems, our group company Web Tasarım Ofisi provides end-to-end support for this kind of technical integration work.
For a team that can resolve similar connectivity and deployment issues for you, explore our custom software service or get in touch with us. We cover a different everyday development snag in our guide to fixing a git push rejected error.
Sources
- MDN Web Docs, Cross-Origin Resource Sharing (CORS), the official technical reference for the CORS mechanism and its related HTTP headers
Frequently asked questions
What does a CORS error actually mean?
It means your browser was not allowed to read the response to a request made to a different origin. The request usually reaches the server and the server does produce a response: what gets blocked is the browser showing that response to your JavaScript code, not the network traffic itself.
Is it safe to use Access-Control-Allow-Origin: *?
For a public API that doesn't require authentication, it's usually fine. But if the request carries credentials (credentials: 'include'), the browser rejects a wildcard origin outright, so you need to return the exact requesting origin instead.
What is a preflight (OPTIONS) request, and why does it cause CORS errors?
Before sending a non-simple request, one with custom headers, using PUT/DELETE, or a JSON body, the browser automatically sends an OPTIONS request first. If the server doesn't answer it with the right headers, the browser never sends the actual request, and you see a preflight error in the console.
Does a CORS error only ever show up in the browser?
Yes. CORS is a security mechanism enforced entirely by the browser; a request from Postman, cURL, or server-to-server isn't subject to it. That's exactly why an API that works fine in Postman but fails in the browser is the classic sign of a CORS error.
How do you fix a CORS error on the WordPress REST API?
You typically hook into rest_api_init in your theme or a small plugin and add the Access-Control-Allow-Origin header manually to the relevant requests; the same header can also be added at the server level via .htaccess or Nginx config. The fix lives in server or hosting configuration, not in the site's content.