Skip to content

fix(clerk-js): keep dev browser token in memory to prevent stale partitioned cookie reads#8161

Merged
brkalow merged 4 commits intomainfrom
bryce/fix-dev-browser-partitioned-cookie-race
Mar 25, 2026
Merged

fix(clerk-js): keep dev browser token in memory to prevent stale partitioned cookie reads#8161
brkalow merged 4 commits intomainfrom
bryce/fix-dev-browser-partitioned-cookie-race

Conversation

@brkalow
Copy link
Member

@brkalow brkalow commented Mar 25, 2026

Summary

  • Introduces an in-memory cache for the dev browser token in createDevBrowser so getDevBrowser() always returns the authoritative value, regardless of document.cookie read ordering
  • Fixes a bug where FAPI requests could use a stale non-partitioned __clerk_db_jwt cookie when partitionedCookies is enabled, since the browser treats partitioned and non-partitioned cookies with the same name as distinct entries

Test plan

  • Unit tests covering in-memory precedence, cookie loss resilience, clear/set behavior, duplicate cookie scenarios, and FAPI interceptor correctness
  • Integration test (Playwright) verifying that when a stale partitioned cookie exists and the page loads with __clerk_db_jwt in the URL, all FAPI requests use the URL token

Made with Cursor

Summary by CodeRabbit

  • Bug Fixes

    • Fixed dev browser token behavior when partitioned cookies are enabled; tokens are now properly sourced from memory instead of stale cookies.
  • Tests

    • Added integration test to verify dev browser token precedence with partitioned cookies.

…itioned cookie reads

When `partitionedCookies` is enabled via Environment, the browser treats
partitioned and non-partitioned cookies with the same name as distinct.
Before this fix, `getDevBrowser()` read directly from `document.cookie`,
which could return a stale non-partitioned duplicate instead of the
correct partitioned value.

This change introduces an in-memory cache for the dev browser token so
that FAPI interceptors always use the authoritative value — whether it
came from the URL query param, a cookie, or a FAPI response header —
regardless of cookie read ordering.

Made-with: Cursor
@changeset-bot
Copy link

changeset-bot bot commented Mar 25, 2026

🦋 Changeset detected

Latest commit: fe8f025

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@clerk/clerk-js Patch
@clerk/chrome-extension Patch
@clerk/expo Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Mar 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Mar 25, 2026 6:29pm

Request Review

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 25, 2026

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@8161

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@8161

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@8161

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@8161

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@8161

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@8161

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@8161

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@8161

@clerk/express

npm i https://pkg.pr.new/@clerk/express@8161

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@8161

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8161

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@8161

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@8161

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@8161

@clerk/react

npm i https://pkg.pr.new/@clerk/react@8161

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@8161

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@8161

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@8161

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@8161

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8161

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@8161

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@8161

commit: 88409f4

@brkalow brkalow requested a review from tmilewski March 25, 2026 04:25
// Hold the dev browser token in memory so it's always available to FAPI
// interceptors, even before Environment resolves and cookies can be written
// with the correct Partitioned attribute.
let devBrowserInMemory: string | undefined;
Copy link
Member Author

Choose a reason for hiding this comment

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

I can't think of a reason why this wouldn't be safe. Potentially if there are already multiple dev browser cookies and a different value would have been read from cookies, but that would be a separate issue for us.

  • Dev browser should be unique per device per instance
  • Using this in-memory value should actually be more efficient and avoid unnecessary cookie reads
  • Any time the dev browser cooke is mutated on the client this value is updated accordingly

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: f6c555ac-96c6-463f-ae02-1c0f94445d5a

📥 Commits

Reviewing files that changed from the base of the PR and between 5f859be and 88409f4.

📒 Files selected for processing (1)
  • .changeset/fix-dev-browser-partitioned-cookie.md

📝 Walkthrough

Walkthrough

This pull request introduces an in-memory cache mechanism for the dev browser token in @clerk/clerk-js and adds test coverage for the new behavior. The implementation adds a devBrowserInMemory cache to the createDevBrowser function that is checked first by getDevBrowser() before falling back to the cookie value. The setDevBrowser() and removeDevBrowser() functions are updated to synchronize both the in-memory cache and cookie storage. A new Playwright integration test verifies that a fresh dev browser token from FAPI takes precedence over a stale partitioned cookie value during initial page load. A changeset documents this as a patch fix for @clerk/clerk-js.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and specifically describes the main technical fix: keeping the dev browser token in memory to prevent stale partitioned cookie reads, which matches the core change across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/clerk-js/src/core/auth/devBrowser.ts`:
- Around line 91-94: In setup(), avoid seeding devBrowserInMemory from
devBrowserCookie.get() before legacy cleanup: run the same legacy
non-partitioned cookie removal logic that set() performs (i.e., remove the
legacy/non-partitioned cookie) or otherwise detect whether a partitioned cookie
exists and skip adopting a stale value; in practice update setup() to invoke the
legacy-cookie cleanup routine used by set() (or inline the removal of the old
non-partitioned cookie) before reading devBrowserCookie.get() so
devBrowserInMemory never caches a stale legacy token.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: fb661217-ba4c-4b4b-8159-bc56705d2b93

📥 Commits

Reviewing files that changed from the base of the PR and between 1cf76d1 and 5f859be.

📒 Files selected for processing (3)
  • integration/tests/dev-browser-partitioned-cookies.test.ts
  • packages/clerk-js/src/core/auth/__tests__/devBrowser.test.ts
  • packages/clerk-js/src/core/auth/devBrowser.ts

@brkalow brkalow merged commit 9ca9300 into main Mar 25, 2026
7 of 8 checks passed
@brkalow brkalow deleted the bryce/fix-dev-browser-partitioned-cookie-race branch March 25, 2026 18:28
wobsoriano pushed a commit that referenced this pull request Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants