How to Send Cookies with Fetch in JavaScript

Reynaldi
Reynaldi •

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:

  1. 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.
  2. Cross-origin cookies are increasingly blocked. With SameSite=Lax as 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 header
fetch("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 cookie
const 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 need
const 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 requests
const 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 sourceBrowser’s cookie jar onlyAny value you specify
Cross-domainSubject to SameSite rulesWorks to any domain
Third-party cookiesBeing deprecated by browsersNot affected
Server must supportAccess-Control-Allow-CredentialsNothing, proxy handles CORS
ControlBrowser decides what to sendYou 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.

It's time to build great websites without CORS errors

Try our CORS proxy for free, all features included.

Fix CORS errorsNo credit card required.