Dr.Who
← blog

No Access-Control-Allow-Origin header means the server must add it — the fix is never frontend code

· cors · access-control-allow-origin · browser · api · headers

corsaccess-control-allow-originbrowserapiheaders

The error "No Access-Control-Allow-Origin header is present on the requested resource" means the browser made a cross-origin request, the server responded, but that response did not include the Access-Control-Allow-Origin header the browser requires to hand the result to your JavaScript. CORS is enforced by the browser and configured on the server, so this is not something you can fix in frontend code — the API itself must return the header. The request usually succeeded on the network; the browser simply refused to expose the response because the permission header was missing.

Why you cannot fix this in the browser

CORS is a browser security mechanism. When your page on one origin (say https://app.example.com) calls an API on another (https://api.example.com), the browser sends the request, reads the response headers, and only reveals the body to your code if the server explicitly opted in. No fetch option, no header you set on the request, and no client-side configuration can grant that permission — only the server's response can. Setting a header like Access-Control-Allow-Origin on your request does nothing; it is a response header.

The fix is to make the API return it. The server should respond with the allowed origin:

Access-Control-Allow-Origin: https://app.example.com

You can return a single specific origin, or maintain a whitelist server-side and echo back the request's Origin header when it matches. Do not reach for * reflexively: Access-Control-Allow-Origin: * works for public, non-credentialed reads, but the wildcard is forbidden the moment the request carries cookies or credentials, so a whitelist-and-echo approach is the more durable default.

Non-simple requests need a preflight too

Adding the header to the actual response is not always enough. For anything beyond a "simple" request — a method other than GET/HEAD/POST, a non-simple Content-Type like application/json, or custom headers such as Authorization — the browser first sends a preflight OPTIONS request and will not send the real request unless that preflight succeeds. The server must answer the OPTIONS with the matching permissions:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 600

If the preflight comes back without these — or returns a 4xx/5xx — the browser reports a CORS failure and the real request never leaves. A missing Access-Control-Allow-Origin error is often actually a failed preflight, so check the OPTIONS response, not just the GET.

When you do not control the API

Sometimes the API belongs to a third party you cannot reconfigure. In that case the only legitimate workaround is to route the call through your own backend: your server (or a small proxy) calls the third-party API server-to-server, where CORS does not apply at all, and your frontend talks to your own same-origin endpoint. This keeps secrets off the client and sidesteps the missing header entirely. Browser extensions or "disable CORS" flags are not a fix — they only mask the problem on your own machine.

See exactly which CORS headers your API returns →

Further reading