Skip to content

fix(cookies): keep domain-scoped deletion in name-keyed cookie stores#258

Merged
mandarini merged 2 commits into
supabase:mainfrom
thribhuvan003:fix/cookie-domain-deletion-order
Jul 14, 2026
Merged

fix(cookies): keep domain-scoped deletion in name-keyed cookie stores#258
mandarini merged 2 commits into
supabase:mainfrom
thribhuvan003:fix/cookie-domain-deletion-order

Conversation

@thribhuvan003

Copy link
Copy Markdown
Contributor

since #240 added the host-only also-clear, removeItem, the setItem chunk cleanup and applyServerStorage emit two entries for the same cookie name when a domain is configured — the domain clear first, then the host-only one. next.js backs its cookie store with a map keyed by name only (ResponseCookies from @edge-runtime/cookies), so the second host-only entry (no Domain) overwrites the first and only that reaches the browser. browsers match cookies by (name, domain, path), so the domain-scoped session cookie the library itself set never gets deleted and signOut() leaves the session stuck for any project that sets cookieOptions.domain.

this flips the order so the host-only clear comes first and the domain clear last. name-keyed stores keep the domain deletion (the one that matches what we set) and only drop the best-effort host-only cleanup; adapters that emit a Set-Cookie per entry still get both. no behaviour change when no domain is configured.

the tests added in #240 asserted the payload order, so they passed even though the collapse happens one layer down in the cookie store — i added a test that runs removeItem through a name-keyed store and checks the surviving deletion still carries the domain (fails on the old order), and updated the three existing order assertions to match.

fixes #256

since supabase#240 added the host-only also-clear, removeItem, setItem cleanup and applyServerStorage emit two entries for the same cookie name when a domain is configured: the domain clear first, then the host-only one. next.js backs its cookie store with a map keyed by name only, so the host-only entry (no Domain) overwrites the domain one and only that reaches the browser. browsers match cookies by (name, domain, path), so the domain-scoped session cookie the library set is never actually deleted and signOut leaves the session stuck.

this flips the order so the host-only clear comes first and the domain clear last. name-keyed stores keep the domain deletion (the one that matches what we set) and only drop the best-effort host-only cleanup; adapters that emit a Set-Cookie per entry still get both. no change when no domain is configured.

added a test that runs removeItem through a name-keyed store and checks the surviving deletion still carries the domain - it fails on the old order. updated the three existing order assertions to match.

fixes supabase#256
@thribhuvan003
thribhuvan003 requested review from a team as code owners July 9, 2026 16:35
@mandarini

Copy link
Copy Markdown
Contributor

Hi @thribhuvan003, thank you so much for contributing to Supabase! 💚

This is a great catch and a great fix. I went and pulled the actual @edge-runtime/cookies source that Next.js ships to confirm the root cause myself, and you are exactly right: ResponseCookies stores everything in a Map keyed only by cookie name, so the later set() call always wins. Reordering so the host-only clear goes first and the domain clear goes last is the right call, and it is nice that it needs no change at all when no domain is configured.

One thing I would like to see before merging: the new describe("name-keyed cookie store (Next.js ResponseCookies semantics)") test is a really good idea, but it calls createStorageFromOptions(..., false) and exercises storage.removeItem, which is the browser storage path. createServerClient, which is what actually powers signOut() in Next.js Route Handlers and Server Actions (the exact scenario in #256), goes through applyServerStorage instead. Would you be up for adding an equivalent name-keyed-store simulation test that runs through applyServerStorage? The existing applyServerStorage test still only checks the emitted order, so it would not catch a regression in the map-collapse behavior specifically for that path the way your new test does for removeItem.

Everything else here looks solid to me, the reorder is applied consistently across all three sites and I did not find any interaction with the dedup logic from #246.

Thank you again for digging into this and fixing it properly rather than just papering over the symptom, it makes a real difference for anyone running cookieOptions.domain in production.

@mandarini mandarini left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read my comment above please! THank you!

@thribhuvan003

Copy link
Copy Markdown
Contributor Author

thanks for the thorough review @mandarini, and for pulling the edge-runtime source to double check it! 💚

good call on the server path — added a test that runs the same name-keyed map through applyServerStorage (the signOut route-handler path from #256). it does catch the collapse specifically: on the old ordering it fails with the domain deletion getting overwritten (expected undefined to be '.example.com'), and passes with the reorder. full suite still green.

@mandarini
mandarini merged commit d3a8a98 into supabase:main Jul 14, 2026
2 checks passed
mandarini pushed a commit that referenced this pull request Jul 14, 2026
🤖 I have created a release *beep* *boop*
---


## [0.12.3](v0.12.2...v0.12.3)
(2026-07-14)


### Bug Fixes

* **cookies:** keep domain-scoped deletion in name-keyed cookie stores
([#258](#258))
([d3a8a98](d3a8a98)),
closes [#256](#256)

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: supabase-releaser[bot] <223506987+supabase-releaser[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

signOut() never deletes cookies with a configured domain in Next.js — host-only clear variant from #240 overwrites the domain deletion (0.12.0)

2 participants