DEV Community

Cover image for Understanding Cookie Transmission in Cross-Origin API Requests
Parmesh B
Parmesh B

Posted on

Understanding Cookie Transmission in Cross-Origin API Requests

The Problem That Cost Me 2 Hours

Picture this: Your frontend is calling a public API endpoint. No authentication barriers, no token requirements—just a simple, open endpoint. Everything should work smoothly, right?

Wrong.

I spent over 2 hours pulling my hair out because my cookies weren't being sent with the requests. The API was public, my code looked fine, but the browser simply refused to include the cookies I needed.

After diving deep into browser behavior, CORS policies, and cookie attributes, I finally understood what was happening. Here's everything I learned so you don't have to waste your afternoon debugging the same issue.

The Big Misconception: Public ≠ Cookie Freedom

Here's the crucial insight that took me way too long to understand:

Just because an endpoint is public doesn't mean the browser will freely send cookies to it.

A "public API" simply means there's no authentication barrier blocking access. But whether cookies are included in requests depends on an entirely different set of rules around:

  • Cookie attributes

  • Cross-origin request policies

  • CORS configuration

The browser doesn't care if the endpoint is "public" or "private"—it cares about security, and it enforces strict rules to protect users from attacks like CSRF (Cross-Site Request Forgery).

The Three Factors That Control Cookie Transmission

After hours of debugging and reading documentation, I identified three critical factors that determine whether cookies are sent with cross-origin requests:

1. SameSite Attribute: The Gatekeeper

The SameSiteattribute is the first line of defense. It tells the browser when a cookie should be included:

SameSite=Strict

  • Cookie is ONLY sent on same-site requests

  • Cross-site requests? Forget about it—no cookies for you

  • Most secure, but breaks legitimate cross-site use cases

SameSite=Lax (default in modern browsers)

  • Cookie sent on same-site requests

  • Also sent on top-level navigations (like clicking a link)

  • NOT sent on cross-site API calls (like fetch or axios requests)

SameSite=None; Secure

  • Allows cookies on cross-site requests

  • MUST be paired with the Secure flag

  • Required for cookies to work in cross-origin API scenarios

Key takeaway: If your backend sets cookies without SameSite=None; Secure, they won't be sent in cross-origin API calls, period.

2. Client-Side Configuration: Ask for Credentials

Even with the right cookie attributes, you need to explicitly tell the browser to include cookies in cross-origin requests.

With Fetch API:

javascript

fetch({your_endpoint}, {
credentials: 'include' // This is the magic line
})

With Axios:

javascript

axios.get({your_endpoint}, {
withCredentials: true // Enable cookie transmission
})

Without these flags, the browser assumes you don't want cookies sent cross-origin, and it won't include them—even if everything else is configured correctly.

3. Server-Side CORS Headers: The Final Permission

Here's where my 2-hour bug was hiding: the server must explicitly allow credentialed requests with proper CORS headers.

Required headers:

`Access-Control-Allow-Credentials: true

Critical rules:

  • You CANNOT use Access-Control-Allow-Origin: * with credentials

  • The origin must be specific

  • Both headers must be present for cookies to be sent

In my case, the frontend had withCredentials: true, but the backend team hadn't configured these CORS headers. The browser saw the mismatch and silently blocked the cookies.

Other Cookie Flags Worth Understanding

While debugging, I also learned about two other important cookie attributes:

HttpOnly

  • Prevents JavaScript from accessing the cookie via document.cookie

  • Does NOT prevent the browser from sending it in HTTP requests

  • Great for security (prevents XSS attacks from stealing session cookies)

Secure

  • Cookie will ONLY be sent over HTTPS connections

  • Essential for production environments

  • Required when using SameSite=None

My Debugging Story: What Went Wrong

Here's exactly what happened in my case:

  1. Frontend setup: I was using axios with withCredentials: true ✅

  2. Cookie attributes: Backend was setting cookies, but without proper SameSite attributes ❌

  3. CORS headers: The public API team hadn't configured Access-Control-Allow-Credentials or a specific Access-Control-Allow-Origin ❌

The result? The browser looked at this mismatched configuration and said, "Nope, not sending those cookies."

Once the backend team added:

  • SameSite=None; Secure to the cookies

  • Access-Control-Allow-Credentials: true

Everything worked perfectly.

The Complete Checklist for Cross-Origin Cookies

Before you waste hours debugging like I did, check these three things:

✅ Backend Cookie Configuration

  • Cookies set with SameSite=None; Secure

  • Secure flag present (requires HTTPS)

  • HttpOnly flag if you don't need JS access

✅ Frontend Request Configuration

  • withCredentials: true (Axios) or credentials: 'include' (Fetch)

  • Requests are going to the correct domain

✅ Server CORS Headers

  • Access-Control-Allow-Credentials: true

  • Access-Control-Allow-Origin set to a specific origin (NOT *)

  • Headers present on both preflight and actual responses

All three must align perfectly, or cookies won't be sent.

Pro Debugging Tips

Chrome DevTools is your friend:

  1. Open DevTools → Network tab

  2. Click on the failed request

  3. Go to the "Cookies" tab

  4. Look for blocked cookies and the reason why

The browser will tell you exactly why cookies were blocked—you just need to know where to look!

The Bigger Picture: Why Browsers Are So Strict

You might wonder: "Why make this so complicated? Why not just send cookies everywhere?"

The answer is security. These restrictions exist to protect users from:

  • CSRF attacks: Malicious sites make requests on your behalf to legitimate sites where you're logged in

  • Data leakage: Third-party sites accessing your cookies and session data

  • Privacy violations: Tracking users across different websites

The browser assumes cookies contain sensitive data (like session tokens), so it requires explicit permission from both the client AND server before allowing cross-origin transmission.

Yes, it makes development harder. But it also keeps users safe.

Key Takeaways

After spending 2 hours on this bug, here's what I want you to remember:

"Public endpoint" doesn't mean "free cookie access"—browsers enforce strict security rules regardless of API accessibility

Three things must align:

  • Cookie attributes (SameSite=None; Secure)

  • Client configuration (withCredentials: true)

  • Server CORS headers (Allow-Credentials + specific Allow-Origin)

Silent failures are the worst—browsers often block cookies without obvious error messages, so know how to use DevTools to debug

This is a backend AND frontend problem—you can't fix it from just one side

Security over convenience—these restrictions exist for good reasons, even if they complicate development

Final Thoughts

Cross-origin cookie handling is one of those topics that seems simple until you actually need to implement it. The combination of cookie attributes, CORS policies, and browser security rules creates a complex system that's easy to misconfigure.

But once you understand the rules, debugging becomes much easier. Instead of randomly trying different configurations, you can systematically check each requirement and identify exactly what's missing.

I hope this post saves you from the 2 hours of frustration I went through. If you're working with public APIs and need to send cookies cross-origin, bookmark this checklist—you'll thank yourself later!

Top comments (0)