How to Send Cookies with Fetch in JavaScript
On This Page
The Cookie header is a forbidden header name in the browser, which means JavaScript cannot set it using fetch(). In this article, you’ll learn why browsers block it, how to bypass the restriction using a server-side proxy, and how to manage session cookies across requests.
The Code
fetch("https://proxy.corsfix.com/?https://api.example.com/dashboard", { headers: { "x-corsfix-headers": JSON.stringify({ Cookie: "session_id=abc123; user_pref=darkmode", }), },}) .then((response) => response.json()) .then((data) => console.log(data));That’s it. Instead of setting Cookie directly (which the browser ignores), you pass it inside x-corsfix-headers. Corsfix reads those instructions and sets the real Cookie header server-side before forwarding the request to the target API.
For local development, this works instantly without registration. For live websites, set up your domain (takes 30 seconds).
What’s Actually Happening (and Why fetch Won’t Let You Do It)
The Cookie header is on the browser’s forbidden header names list. The browser exclusively controls this header for security reasons, deciding which cookies to attach based on the request’s domain, path, and SameSite rules.
This means two things:
- You can’t set arbitrary cookies. Even
credentials: "include"only sends cookies the browser already has in its jar for that domain. You can’t inject a session token you got from somewhere else. - Cross-origin cookies are increasingly blocked. With
SameSite=Laxas the default and third-party cookie deprecation rolling out,credentials: "include"is becoming less reliable for cross-domain use cases.
// This does nothing, the browser silently ignores the Cookie headerfetch("https://api.example.com/dashboard", { headers: { Cookie: "session_id=abc123", },});In Node.js or any server-side runtime, you can set Cookie freely. The restriction is purely in the browser. A proxy bridges the gap by accepting cookie values from your frontend and applying them server-side, where the browser’s rules don’t apply.
The Full Session Flow: Login, Store, Reuse
Where this gets interesting is managing a full session lifecycle through the proxy. When you authenticate against a third-party API, the server responds with Set-Cookie headers. Normally the browser stores those automatically, but since the response came through a proxy domain, the cookies won’t be saved for the target domain.
Corsfix exposes the target’s Set-Cookie value in a response header called x-corsfix-set-cookie, so you can capture it and manage the session yourself.
Here’s a complete login-then-use-session flow:
// Step 1: Authenticate and capture the session cookieconst loginResponse = await fetch( "https://proxy.corsfix.com/?https://api.example.com/login", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username: "user", password: "pass" }), });
// Step 2: Read the Set-Cookie from the proxied response// The value looks like "session_id=abc123; Path=/; HttpOnly, theme=dark; Path=/"const setCookie = loginResponse.headers.get("x-corsfix-set-cookie");
// Step 3: Parse out just the name=value pairs// Multiple Set-Cookie values are comma-separated, and each has// attributes after the first semicolon that we don't needconst cookieValue = setCookie ?.split(",") .map((c) => c.trim().split(";")[0]) .join("; ");// Result: "session_id=abc123; theme=dark"
if (cookieValue) { sessionStorage.setItem("api_session", cookieValue);}
// Step 4: Use the stored cookie in subsequent requestsconst saved = sessionStorage.getItem("api_session");
const dashboardResponse = await fetch( "https://proxy.corsfix.com/?https://api.example.com/dashboard", { headers: { "x-corsfix-headers": JSON.stringify({ Cookie: saved, }), }, });
const data = await dashboardResponse.json();Since you’re managing cookies manually, you’re responsible for sending them on every request. But the tradeoff is full control. You decide exactly what gets sent, to which domain, with no SameSite restrictions or third-party cookie issues getting in the way.
Why Not Just Use credentials: “include”?
credentials: "include" tells the browser to attach its own cookies to the request. It works well for first-party APIs, but falls apart for third-party integrations:
credentials: "include" | Proxy with x-corsfix-headers | |
|---|---|---|
| Cookie source | Browser’s cookie jar only | Any value you specify |
| Cross-domain | Subject to SameSite rules | Works to any domain |
| Third-party cookies | Being deprecated by browsers | Not affected |
| Server must support | Access-Control-Allow-Credentials | Nothing, proxy handles CORS |
| Control | Browser decides what to send | You decide what to send |
If you’re integrating with an API you don’t control and need to pass specific session cookies, credentials: "include" simply can’t do it. You need a proxy.
Conclusion
Use a server-side proxy like Corsfix to send a Cookie header with fetch in JavaScript. Pass your cookie values inside x-corsfix-headers, and Corsfix sets the real Cookie header on the outbound request. To read Set-Cookie from the response, use the x-corsfix-set-cookie response header and parse out the name=value part for subsequent requests.
Corsfix handles the Cookie header override along with other forbidden headers server-side, so you can focus on building your app instead of managing proxy infrastructure.