InterviewsVector

Fix: Refused to set unsafe header Origin (XMLHttpRequest)

Quick answer

Origin is a forbidden header name: the browser controls it and refuses any attempt to set it with XMLHttpRequest.setRequestHeader, logging 'Refused to set unsafe header Origin'. You cannot fix this from client-side JavaScript, and you should not try — spoofing Origin would defeat CORS. Remove the setRequestHeader call and configure the server to allow your real origin with an Access-Control-Allow-Origin response header.

You tried to set the Origin header on a request and the browser logged:

Refused to set unsafe header "Origin"

The header was silently dropped. This is by design, and the fix is not on the client.

Why the browser refuses

Origin is a forbidden header name. The browser sets it automatically to reflect the true origin of the page making the request, and the entire CORS security model depends on the server being able to trust that value.

If JavaScript could rewrite Origin, any page could claim to be any site — and the same-origin policy would protect nothing. So the browser ignores your attempt:

const xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data");
xhr.setRequestHeader("Origin", "https://example.com"); // silently ignored + warning
xhr.send();
Refused to set unsafe header Origin

It's a warning, not a failure

The message is logged at warning level. The request still goes out — just with the browser's own correct Origin, not yours. So if your request is actually failing, this warning is a red herring: the real problem is almost always a missing or mismatched CORS response header on the server.

The real fix: configure CORS on the server

Remove the setRequestHeader("Origin", …) call entirely, then have the server return the appropriate CORS headers.

Access-Control-Allow-Origin: https://your-site.com

Prefer naming the specific origin over *. A wildcard cannot be combined with credentials, and it allows every site on the internet to call your API from the browser.

Concrete examples:

// Express
app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "https://your-site.com");
  res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
  res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
  next();
});

If the request uses a non-simple method or custom headers, the browser first sends a preflight OPTIONS request — the server must answer that too, with the Allow-Methods and Allow-Headers above.

For cookies or auth:

Access-Control-Allow-Origin: https://your-site.com   # must be specific, not *
Access-Control-Allow-Credentials: true

Local development shortcut

During development, avoid CORS entirely with a dev-server proxy so the browser sees a same-origin request:

// vite.config.js
export default {
  server: {
    proxy: { "/api": "https://api.example.com" }
  }
}

Angular has proxy.conf.json; webpack-dev-server has devServer.proxy. No header forging required.

The full forbidden-header list

You can't set any of these from browser JavaScript — the browser owns them:

Origin, Host, Referer, Cookie, Connection, Content-Length, Date, DNT, Keep-Alive, TE, Trailer, Transfer-Encoding, Upgrade, Via, and anything starting with Proxy- or Sec-.

When you genuinely need to send a custom Origin

Only non-browser clients can do this — curl, Node's http/fetch on the server, Postman — because they aren't bound by the same-origin policy:

curl -H "Origin: https://example.com" https://api.example.com/data

If you're in a browser and think you need to spoof Origin, you almost certainly need a server-side CORS change or a proxy instead.

Key takeaways

  • Origin is on the forbidden header list, alongside Host, Referer, Cookie, and Connection — browsers set these and scripts cannot override them.
  • The message is a warning, not an exception: the request still goes out, just without your header, so it will not break execution.
  • You cannot spoof Origin from browser JavaScript by design — if you could, CORS would provide no protection at all.
  • The real fix is server-side: return Access-Control-Allow-Origin naming the calling origin, not a client-side header hack.
  • For local development, use a dev-server proxy so requests appear same-origin instead of trying to forge headers.
  • Server-to-server clients (curl, Node, Postman) are not browsers and can set Origin freely — the restriction only applies to browser JavaScript.

Frequently asked questions

Why does the browser refuse to set the Origin header?

Origin is a forbidden header name in the Fetch specification. The browser sets it automatically to reflect the true origin of the page, and CORS depends on the server trusting that value. If scripts could rewrite it, any site could impersonate any origin and the same-origin policy would be meaningless.

Is 'Refused to set unsafe header Origin' an error that breaks my request?

No. The browser logs a warning and ignores the setRequestHeader call, then sends the request with its own correct Origin. If the request is failing, the cause is almost always a missing or mismatched CORS response header on the server, not this warning.

How do I actually fix the underlying CORS problem?

Configure the server to return Access-Control-Allow-Origin with the requesting origin (or a specific allowed list), plus Access-Control-Allow-Methods and Access-Control-Allow-Headers if you use non-simple methods or custom headers. If credentials are involved, return Access-Control-Allow-Credentials: true and a specific origin rather than a wildcard.

Which other headers can't I set from JavaScript?

The forbidden list includes Origin, Host, Referer, Cookie, Connection, Content-Length, Date, DNT, Keep-Alive, TE, Trailer, Transfer-Encoding, Upgrade, Via, and any header beginning with Proxy- or Sec-. All are controlled by the browser for security or protocol correctness.

Can I work around it during local development?

Yes — route API calls through your dev server's proxy (for example the proxy option in Vite, webpack-dev-server, or Angular's proxy.conf.json). The browser then sees a same-origin request and no CORS preflight occurs, without anyone forging headers.

By Mohammad Wasi

Software Engineering Leader & Technical Author · Updated July 21, 2026


Related Posts