How to Fix CORS Error: "No Access-Control-Allow-Origin" Header

How do you fix a CORS error?
A CORS error means the browser refused to hand a cross-origin response to your JavaScript, because the server did not send the permission headers. You fix it on the server. Add the right Access-Control-Allow-Origin header to the API response and answer the preflight (OPTIONS) request with a success status.
A red message in the console feels urgent, but the cause is usually small. Most of the time you have one missing header or one mistyped address. This guide walks through the checks from the most likely cause to the least likely one.
We keep the scope narrow on purpose. If your local server does not respond at all, read our localhost refused to connect guide first. That problem is a network issue, not CORS.
What is the quick fix for a CORS error, step by step?
First, confirm the problem is really CORS, because several other errors look similar. Then follow this order.
- Open the Network tab in your browser developer tools and find the failed request.
- Check whether the failing request is the preflight (OPTIONS) or the real request.
- Look for the
Access-Control-Allow-Originheader in the response. - Compare its value with the origin in your address bar, character by character.
- For a preflight, check
Access-Control-Allow-MethodsandAccess-Control-Allow-Headers. - If you send cookies or an authorization header, replace the wildcard (*) with an explicit origin and add
Access-Control-Allow-Credentials. - Apply the fix on the server, clear caches, and retry the request.
These seven steps solve most cases. The order is deliberate. The Network tab shows the facts, while the console only summarizes them, so do not skip the first two steps.
Why does a CORS error happen, and what is the same-origin policy?
Browsers enforce the same-origin policy by default. It stops code on one page from reading responses that belong to another origin. As a result, a malicious site cannot use your logged-in session to read data from a different site.
CORS (Cross-Origin Resource Sharing) is a controlled exception to that rule. The server declares which origins may read its responses, using headers. The browser checks those headers and withholds the response if they do not match.
One detail surprises many developers. The request often reaches the server, and the server answers. However, the browser is the one that blocks your code from reading the answer. That is why your server log can show the request while the console shows an error.
The MDN CORS guide and the WHATWG Fetch standard are the primary references if you want the full rules.
What is an origin, and which URLs count as different origins?
An origin combines three parts: scheme, host, and port. If any one of them differs, the browser treats the two URLs as different origins. The path and the query string do not count.
https://app.example.comandhttp://app.example.comdiffer, because the scheme changes.https://app.example.comandhttps://api.example.comdiffer, because the host changes.https://example.comandhttps://example.com:8443differ, because the port changes.https://example.com/aandhttps://example.com/bshare one origin.
For example, during development your front end runs on one port and your API on another. Even on the same machine, those are different origins. Therefore, CORS applies.
Also remember that localhost and 127.0.0.1 count as different hosts. If you allow one in the header but call from the other, you get the error.
Can you turn off a CORS error in the browser or client?
No, the correct and lasting fix does not live in the client. The server makes the CORS decision through headers, and no fetch option can override it. If the response header is missing, the browser still withholds the response.
Many posts suggest browser extensions or launch flags that switch off web security. We do not recommend them. They only work on your own machine, they do not fix the problem for your users, and they leave your browser open to real attacks.
The fetch no-cors mode is not a fix either. Instead, the request goes out, but the response becomes opaque, so your code cannot read it. So the error goes quiet, yet the data stays out of reach.
In short, you fix the problem in one of three places: the API server, the reverse proxy in front of it, or a proxy you control during development. We cover all three below.
What are simple requests and preflight requests?
The browser sends some requests directly. We call them simple requests. For the others, it first sends an OPTIONS request, called a preflight, to ask the server for permission. If the answer is no, the browser never sends the real request.
A simple request uses GET, HEAD, or POST and only safe headers. For POST, the content type must be form data or plain text. The MDN CORS guide lists the exact rules.
In practice, these cases trigger a preflight:
- A POST request with the
application/jsoncontent type. - Methods such as PUT, PATCH, or DELETE.
- Custom headers such as
Authorization.
So that explains the common complaint that GET works but POST fails. Usually the preflight failed, not the POST itself.
The preflight carries no body, and your own code never sees it. The browser creates it automatically. So if your app has no OPTIONS handler, the request meets an unexpected answer.
Which CORS response headers do you need?
The server sends these headers with its response. Each one has a different job, so keep them separate in your mind.
Access-Control-Allow-Originnames the origin that may read the response. It holds one origin or a wildcard.Access-Control-Allow-Methodslists the allowed methods in a preflight answer.Access-Control-Allow-Headerslists the request headers that the real request may use.Access-Control-Allow-Credentialsallows requests with cookies or credentials. Its only valid value istrue.Vary: Origintells caches that the answer changes per origin.
For many APIs, this short set on the preflight answer is enough:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Vary: OriginIf your front end must read custom response headers, also use Access-Control-Expose-Headers. Header names are case insensitive, but values are not. Also keep the origin in lowercase. See the Access-Control-Allow-Origin reference for details.
Why can you not use a wildcard (*) with credentials?
When a request carries cookies, HTTP authentication, or client certificates, the browser rejects Access-Control-Allow-Origin: *. It demands one explicit origin instead.
If you use credentials: "include" in fetch, you need all three of these together:
- The response names one explicit origin in
Access-Control-Allow-Origin. - The response contains
Access-Control-Allow-Credentials: true. - A preflight answer also lists explicit methods and headers, not wildcards.
Many teams want to support several origins here. Because of that, they copy the incoming Origin value into the response. That works, however it is risky. Compare the value with a known allow list before you echo it back.
For the session and token side of this topic, our guide on what a JWT is helps.
Why does the preflight (OPTIONS) request fail?
A failing preflight is the most common cause behind the complaint that GET works but POST fails. Your server may not recognize OPTIONS, or it may push that request through an authentication layer.
For this reason, check these causes in order, from the most likely to the least likely:
- The server answers OPTIONS with 404 or 405. Add the method to your route list.
- An authentication middleware rejects the preflight because it carries no Authorization header. The browser never sends credentials in a preflight, so answer OPTIONS before you authenticate.
- The preflight status is not a success status (2xx).
Access-Control-Allow-Headersmisses a header that your request uses.- The preflight lands on a redirect. Browsers do not follow redirects on a preflight.
In the Network tab, the OPTIONS request shows up as its own row. Read that row first, including its status code and response headers. This check takes seconds, so it often saves hours.
For example, an auth middleware that wraps every route returns 401 for OPTIONS. The browser then shows a CORS error, but the real cause is the middleware order.
What are the most common CORS mistakes?
In the field, we see small typing differences more often than anything else. The browser compares values exactly, so it has no tolerance.
- Wrong origin: the header says
https://example.com, but the page calls fromhttps://www.example.com. - Trailing slash: you write
https://app.example.com/in the header, while an origin has no trailing slash. - http versus https: development uses http, production uses https, and your allow list covers only one.
- Missing port: in local development, the port belongs to the origin.
- Duplicate header: both the app and the reverse proxy add the header, and the browser rejects the double value.
- Several origins in one value: you write two addresses separated by a comma, but the header accepts only one origin.
You catch all of these by placing the response headers next to the address bar in the Network tab.
Notice that none of these mistakes leaves a trace on the server. The server stays silent, and only the browser complains. Therefore, verify the header value by hand for every new environment.
Can a redirect cause a CORS error?
Yes. If your API address returns a redirect, for example from http to https or from a path without a trailing slash to one with it, the CORS check can break. A preflight request never follows a redirect.
Here is a typical example scenario. The front end calls a path without a trailing slash. Then the server answers with a 301 redirect to the slash version. Because that redirect response carries no CORS header, the browser reports an error.
The fix is simple: call the final address directly. That way no redirect sits in the middle, and all headers arrive in a single response.
To see redirect chains, use our free redirect checker. Paste the address and see where it goes, step by step.
Why does the CORS header disappear on 4xx and 5xx responses?
Many frameworks add CORS headers only to successful responses. When the server returns 401, 404, or 500, the middleware may not run, so the header is missing. The browser then shows a CORS error instead of the real one.
That sends you in the wrong direction. You see a CORS warning in the console, yet the real problem is a server error. For instance, authentication failed and the server returned 401.
To diagnose it properly, test the request outside the browser with a short command:
curl -i -X OPTIONS https://api.example.com/orders \
-H "Origin: https://app.example.com" \
-H "Access-Control-Request-Method: POST"Then read the status code and the headers. If the status is 5xx, fix the server error first, because the CORS symptom is secondary. For the general logic of server errors, see our HTTP 500 guide.
How do you read a CORS diagnosis table by error type?
Browsers word their messages differently and change them over time. So the table below shows the meaning of similar warnings, not exact text. For exact wording, check the MDN CORS errors reference.
| Symptom (similar warning) | Likely cause | Fix |
|---|---|---|
| Permission header missing from the response | The server sends no Access-Control-Allow-Origin | Add the header in the API or reverse proxy layer |
| Header value does not match the origin | Wrong host, port, scheme, or trailing slash | Match the value to the address bar origin exactly |
| Wildcard not allowed with credentials | A credentialed request meets * | Use an explicit origin and add Allow-Credentials: true |
| Preflight did not return a success status | OPTIONS returns 401, 404, 405, or 5xx | Answer OPTIONS with 2xx before authentication |
| Request header not allowed | The header is missing from Allow-Headers | Add the header your request uses |
| Redirect during preflight | The request address returns 301 or 302 | Call the final address directly |
| Multiple values in the header | Two layers add the header | Add the header in one place only |
When you use the table, read the console text first and the Network response headers second. Together they reveal the cause almost every time.
How do you work around a CORS error in development with a proxy?
If your dev server has a proxy feature, this is the cleanest route. The front end calls its own origin, and the dev server forwards the request to the API. From the browser's view, the call is same-origin, so CORS never applies.
The big advantage is that you never weaken browser security. It also resembles the production setup, so fewer surprises appear later. Most modern dev tools let you define a path-based proxy with a few lines of settings. The setting name differs per tool, so check your tool's official documentation.
However, this solution is for development only. For production, pick one of two paths:
- Serve the API behind the same origin as the front end, with a reverse proxy that routes by path.
- Keep the API on a separate host and write the CORS headers correctly.
The first option also removes most CORS needs. We explain the idea in our Nginx reverse proxy guide.
A proxy also reduces cookie trouble. Because the request goes to the same origin, cookies travel normally. So many teams pick this route during development.
Where do you add CORS headers behind a reverse proxy or CDN?
Manage the headers in one place only. Decide once whether the app, the reverse proxy, or the CDN adds them, and switch the others off. Otherwise you hit the duplicate header problem.
Adding them in application code lets you version the rules with the code. Adding them in the reverse proxy gives you one setting for all services. If a CDN caches responses, keep Vary: Origin in place. Without it, a response for one origin can reach another.
Here is an example scenario. A team adds the header in the app and also in the reverse proxy. The response shows Access-Control-Allow-Origin twice, and the browser rejects it. The fix, then, is to remove one of them.
Also watch for a common trap in hosting dashboards. A ready-made CORS option may exist at the CDN or hosting level while your app adds its own header. Read the raw response headers to see which layer wrote them.
Configuration syntax differs per server, so read the official documentation and test the change in a staging environment first.
How do you diagnose a CORS error with browser developer tools?
The console tells you what happened, and the Network tab shows why. Use both together.
- Read the console message and note which header is missing or wrong.
- Open the Network tab, select the failed request, and read the response headers.
- Find the
Originrequest header. That is the origin the server saw. - Compare it with
Access-Control-Allow-Originin the response. - For a preflight, inspect the OPTIONS row in the same way.
If you see no error but the response looks empty, you may be looking at a stale cached response. Disable the cache and try again.
If you opened the page from the file system, the origin is "null", and many servers reject it. Use a small local server instead.
Do cookies and SameSite settings get mixed up with CORS?
Yes, often. Both can produce a "credentials are not sent" symptom, yet the causes differ. CORS decides whether your code may read the response. The cookie attributes and request options decide whether the cookie travels with the request.
Check in this order. First, make sure the request enables the credentials option. Then verify that the server sends Access-Control-Allow-Credentials: true. Finally, check that the cookie's SameSite and Secure attributes suit cross-site requests.
So if the cookie does not travel, do not stay stuck on the CORS text. Look at the request in the Network tab and see whether it carries a Cookie header. If not, the problem sits on the cookie side.
Exact behavior can differ between browser versions. Check current rules in the MDN CORS guide and in your browser documentation.
Does a CORS error look different in fetch, XMLHttpRequest, and axios?
No, the rule is the same. Only the look of the error changes. Fetch usually rejects with a vague network error, and the detail appears only in the console. With XMLHttpRequest or axios, you typically see a generic "Network Error" message in the error object.
So your catch block cannot tell you the cause. JavaScript cannot read CORS details, because the browser hides them from the page for security reasons. The console and the Network tab remain your best sources.
Here is a practical tip. Before you show an error to the user, check whether a status code arrived at all. If none arrived, you likely face CORS or a network problem. If one did, the issue sits in the application layer.
The CORS rule does not change between REST and GraphQL either. For the difference between the two styles, read our guide on GraphQL versus REST.
Does the browser cache a preflight, and why do changes not show up right away?
Yes, because browsers may cache a preflight result for a while. The server suggests a duration with Access-Control-Max-Age, and each browser applies its own upper limit. Check the documentation for the current limits.
This also causes a side effect. You fix the header on the server, but the browser keeps using the old preflight result. So you think the fix failed.
First, disable the cache in developer tools and hard reload the page. Then repeat the request in a private window. If the result changes, then the cache was the cause.
In production, avoid very long cache durations. A wrong setting then stays in your users' browsers until it expires.
Example scenario: how does diagnosis go when the front end and API use different hosts?
This is an example scenario, not a real client case. The front end runs on https://app.example.com and the API on https://api.example.com. Also, the login page loads data with GET, but the sign-up form fails on POST.
- First, the console warns that the preflight failed.
- Then the Network tab shows the OPTIONS row with status 401.
- The API authentication layer tries to authenticate OPTIONS too.
- You reorder the middleware so OPTIONS gets a 2xx answer before authentication.
- You add an
Access-Control-Allow-Originheader that names the origin explicitly. - Finally, you retry the sign-up form.
In this example, the CORS setting was not the problem. The middleware order was. So writing a header alone is not enough; you must understand which layer sees the request first.
How do you prevent a CORS error for good?
A lasting fix moves the CORS setup from hard-coded values into configuration. That way development, staging, and production each get their own allow list. This checklist helps:
- Keep allowed origins in a list and define one per environment.
- Write the incoming
Origininto the response only when it appears in the list. - Answer OPTIONS before authentication.
- Add CORS headers to error responses too.
- Keep
Vary: Originon every caching layer. - Generate the header in one layer only.
- Run an automated smoke test after each deployment to verify the preflight.
Also add an integration test if the error keeps coming back. The test sends an OPTIONS request from a different origin and checks the headers. Then you catch the next regression before it reaches production.
Is CORS a security measure or just a roadblock?
CORS is not an authorization system. It does not block requests from reaching your server. It only controls whether the browser hands the response to page code. An attacker can send the same request from outside a browser with ease.
So a CORS setting never replaces API security. You still need authentication, authorization, and input validation. For common web risks, see our OWASP Top 10 guide.
On the other hand, a policy that is too broad creates real risk. Allowing every origin and enabling credentials can let other sites read data on behalf of your user. Keep the allow list narrow.
If you are new to the concept, our what is an API guide covers the basics.
How can Talha Aslan and team help with this?
Our team works on web apps, API integrations, and release infrastructure. CORS problems usually appear when different teams write the front end and the server, or when a project moves to a new domain.
If your project spans several hosts, a reverse proxy, and a CDN, diagnosing it together is faster. Depending on your scope, you can request a quote for our custom software development service.
This article is not legal or security advice. For tool-specific details, always read the official documentation of the tool you use.



