Skip to content

feat(auth): use partitioned cookies with fallback for dual mode#12536

Draft
rexxars wants to merge 1 commit intomainfrom
rexxars/studio-auth-flow
Draft

feat(auth): use partitioned cookies with fallback for dual mode#12536
rexxars wants to merge 1 commit intomainfrom
rexxars/studio-auth-flow

Conversation

@rexxars
Copy link
Copy Markdown
Member

@rexxars rexxars commented Mar 30, 2026

Description

Replaces the Studio's post-login auth flow with a new /auth/exchange endpoint to fix partitioned cookie issues.

  • The old flow tried cookie-based /users/me first, then fell back to exchanging the session ID for a token via /auth/fetch. This broke because the Partitioned cookie set during the transfer redirect is stored under the API host's partition key, not the Studio's - so the cookie is never sent on subsequent cross-site fetches.
  • The new flow calls /auth/exchange?sid=... with credentials: include, which both sets a cookie under the correct partition key and returns the token in the response body. It then probes /users/me with each auth method (cookie and/or token, depending on loginMethod) in parallel to determine which one actually works.
  • Cookie mode now sends type=dual to the auth provider instead of type=cookie, so a session ID is always returned in the hash.
  • The AuthBoundary now has an error state that prevents flashing login providers when auth fails after a redirect. Instead it shows an appropriate error message ("Cookies blocked" for cookie-only mode, "Authentication failed" with retry for other modes).

What to review

  • createAuthStore.ts has the core flow rewrite - the three-step exchange/probe/decide logic in handleCallbackUrl, plus two new helpers (probeCurrentUser, exchangeSessionForToken)
  • The race condition guard in AuthBoundary.tsx (the setStatus callback form that prevents state$ from overriding the error state)
  • The createHrefForProvider change is small but important - cookie mode now sends type=dual

All changes are in the sanity package.

Testing

No automated tests added. The auth flow depends on real browser cookie behavior, cross-origin fetch, and server-side session management that can't be meaningfully mocked in jsdom. The existing test suite passes with no regressions.

Manual testing needed:

  • Login with dual mode (default) - should prefer cookie auth when available, fall back to token
  • Login with cookie-only mode in a browser that blocks third-party cookies - should show "Cookies blocked" error
  • Login with token-only mode - should store token and use bearer auth
  • Cold load when already authenticated - should work as before

Notes for release

N/A - Part of auth infrastructure improvements. No user-facing API changes.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 30, 2026

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

Project Deployment Actions Updated (UTC)
page-building-studio Ready Ready Preview, Comment Mar 30, 2026 10:45pm
test-studio Ready Ready Preview, Comment Mar 30, 2026 10:45pm

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 30, 2026

🧪 E2E Preview environment

🔑 Environment Variables for Local Testing

This is the preview URL for the E2E tests: https://e2e-studio-3ts5eu9jk.sanity.dev

To run the E2E tests locally, you can use the following environment variables, then run pnpm test:e2e --ui to open the Playwright test runner.

💬 Remember to build the project first with pnpm build:e2e.

  SANITY_E2E_PROJECT_ID=ittbm412
  SANITY_E2E_BASE_URL=https://e2e-studio-3ts5eu9jk.sanity.dev
  SANITY_E2E_DATASET="update depending the project you want to test (pr-12536-chromium-23771369421 || pr-12536-firefox-23771369421 )"
  SANITY_E2E_DATASET_CHROMIUM=pr-12536-chromium-23771369421
  SANITY_E2E_DATASET_FIREFOX=pr-12536-firefox-23771369421

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 30, 2026

📊 Playwright Test Report

Download Full E2E Report

This report contains test results, including videos of failing tests.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 30, 2026

📦 Bundle Stats — sanity

Compared against main (abc296dc) · v5.18.0 (npm)

Metric Value vs main (abc296d) vs v5.18.0
Internal (raw) 4.39 MB +3.7 KB, +0.1% +10.8 KB, +0.2%
Internal (gzip) 1.01 MB +827 B, +0.1% +2.5 KB, +0.2%
Bundled (raw) 12.05 MB +3.7 KB, +0.0% -36.0 KB, -0.3%
Bundled (gzip) 2.71 MB +885 B, +0.0% -6.9 KB, -0.2%
Import time 1.55s +3ms, +0.2% +59ms, +4.0%
Details
  • Import time regressions over 10% are flagged with ⚠️
  • Treemap artifacts are attached to the CI run for detailed size analysis
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

@github-actions
Copy link
Copy Markdown
Contributor

📚 TypeDoc Generation Result

TypeDoc generated successfully!

  • File size: 8.1M
  • Total exports: 1057
  • Artifact: sanity-typedoc-041f568878d8e376a62228e0e1dcde7167529e33

The TypeDoc JSON file has been generated and validated. All documentation scripts completed successfully.

@github-actions
Copy link
Copy Markdown
Contributor

Preview this PR with pkg.pr.new

Run the Sanity CLI

npx https://pkg.pr.new/@sanity/cli@23db03f <command>

...Or upgrade project dependencies

pnpm logo Using pnpm

📦 sanity
pnpm install https://pkg.pr.new/sanity@c259f04
📦 @sanity/vision
pnpm install https://pkg.pr.new/@sanity/vision@c259f04
📦 Other packages…
📦 groq
pnpm install https://pkg.pr.new/groq@c259f04
📦 @sanity/diff
pnpm install https://pkg.pr.new/@sanity/diff@c259f04
📦 @sanity/mutator
pnpm install https://pkg.pr.new/@sanity/mutator@c259f04
📦 @sanity/schema
pnpm install https://pkg.pr.new/@sanity/schema@c259f04
📦 @sanity/types
pnpm install https://pkg.pr.new/@sanity/types@c259f04
📦 @sanity/util
pnpm install https://pkg.pr.new/@sanity/util@c259f04

npm logo Using npm

📦 sanity
npm install https://pkg.pr.new/sanity@c259f04
📦 @sanity/vision
npm install https://pkg.pr.new/@sanity/vision@c259f04
📦 Other packages…
📦 groq
npm install https://pkg.pr.new/groq@c259f04
📦 @sanity/diff
npm install https://pkg.pr.new/@sanity/diff@c259f04
📦 @sanity/mutator
npm install https://pkg.pr.new/@sanity/mutator@c259f04
📦 @sanity/schema
npm install https://pkg.pr.new/@sanity/schema@c259f04
📦 @sanity/types
npm install https://pkg.pr.new/@sanity/types@c259f04
📦 @sanity/util
npm install https://pkg.pr.new/@sanity/util@c259f04

View Commit (c259f04)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 30, 2026

⚡️ Editor Performance Report

Updated Mon, 30 Mar 2026 22:54:35 GMT

Benchmark reference
latency of sanity@latest
experiment
latency of this branch
Δ (%)
latency difference
arrayI18n (simple-en) 55.6 efps (18ms) 51.3 efps (20ms) +2ms (+8.3%)
article (title) 37.0 efps (27ms) 39.2 efps (26ms) -2ms (-5.6%)
article (body) 45.7 efps (22ms) 45.9 efps (22ms) -0ms (-0.5%)
article (string inside object) 42.6 efps (24ms) 45.5 efps (22ms) -2ms (-6.4%)
article (string inside array) 50.0 efps (20ms) 55.6 efps (18ms) -2ms (-10.0%)
recipe (name) 90.9 efps (11ms) 99.9+ efps (10ms) -1ms (-/-%)
recipe (description) 50.0 efps (20ms) 54.1 efps (19ms) -2ms (-7.5%)
recipe (instructions) 99.9+ efps (6ms) 99.9+ efps (6ms) -0ms (-/-%)
singleString (stringField) 99.9+ efps (7ms) 99.9+ efps (7ms) +1ms (-/-%)
synthetic (title) 50.0 efps (20ms) 50.0 efps (20ms) +0ms (-/-%)
synthetic (string inside object) 55.6 efps (18ms) 54.1 efps (19ms) +1ms (+2.8%)

efps — editor "frames per second". The number of updates assumed to be possible within a second.

Derived from input latency. efps = 1000 / input_latency

Detailed information

🏠 Reference result

The performance result of sanity@latest

Benchmark latency p75 p90 p99 blocking time test duration
arrayI18n (simple-en) 18ms 21ms 25ms 45ms 0ms 5.8s
article (title) 27ms 34ms 59ms 72ms 99ms 7.9s
article (body) 22ms 35ms 51ms 109ms 191ms 5.4s
article (string inside object) 24ms 28ms 40ms 63ms 21ms 6.4s
article (string inside array) 20ms 21ms 24ms 62ms 6ms 6.5s
recipe (name) 11ms 16ms 20ms 54ms 0ms 5.5s
recipe (description) 20ms 23ms 26ms 31ms 0ms 4.5s
recipe (instructions) 6ms 9ms 11ms 30ms 0ms 3.0s
singleString (stringField) 7ms 9ms 11ms 20ms 0ms 4.6s
synthetic (title) 20ms 25ms 52ms 91ms 1262ms 9.5s
synthetic (string inside object) 18ms 19ms 24ms 96ms 989ms 8.7s

🧪 Experiment result

The performance result of this branch

Benchmark latency p75 p90 p99 blocking time test duration
arrayI18n (simple-en) 20ms 21ms 24ms 44ms 7ms 6.3s
article (title) 26ms 36ms 53ms 95ms 72ms 7.4s
article (body) 22ms 31ms 57ms 98ms 198ms 5.5s
article (string inside object) 22ms 27ms 43ms 67ms 0ms 6.3s
article (string inside array) 18ms 21ms 25ms 48ms 9ms 6.1s
recipe (name) 10ms 15ms 24ms 59ms 0ms 5.5s
recipe (description) 19ms 21ms 25ms 32ms 0ms 4.4s
recipe (instructions) 6ms 8ms 11ms 25ms 0ms 3.0s
singleString (stringField) 7ms 9ms 11ms 19ms 0ms 4.5s
synthetic (title) 20ms 24ms 48ms 142ms 1287ms 9.5s
synthetic (string inside object) 19ms 20ms 26ms 89ms 1016ms 8.6s

📚 Glossary

column definitions

  • benchmark — the name of the test, e.g. "article", followed by the label of the field being measured, e.g. "(title)".
  • latency — the time between when a key was pressed and when it was rendered. derived from a set of samples. the median (p50) is shown to show the most common latency.
  • p75 — the 75th percentile of the input latency in the test run. 75% of the sampled inputs in this benchmark were processed faster than this value. this provides insight into the upper range of typical performance.
  • p90 — the 90th percentile of the input latency in the test run. 90% of the sampled inputs were faster than this. this metric helps identify slower interactions that occurred less frequently during the benchmark.
  • p99 — the 99th percentile of the input latency in the test run. only 1% of sampled inputs were slower than this. this represents the worst-case scenarios encountered during the benchmark, useful for identifying potential performance outliers.
  • blocking time — the total time during which the main thread was blocked, preventing user input and UI updates. this metric helps identify performance bottlenecks that may cause the interface to feel unresponsive.
  • test duration — how long the test run took to complete.

@github-actions
Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 39.63% 26020 / 65642
🔵 Statements 32.08% 33776 / 105254
🔵 Functions 28.45% 5249 / 18446
🔵 Branches 24.54% 20588 / 83886
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/sanity/src/core/store/_legacy/authStore/createAuthStore.ts 37.03% 30.95% 54.16% 36.64% 32, 38, 49-51, 62, 66, 77-81, 91-92, 99-102, 107-113, 133-198, 226, 230, 260-445, 450
packages/sanity/src/core/store/_legacy/authStore/createLoginComponent.tsx 1.68% 0% 3.33% 3% 26-92, 103-138, 223-273
packages/sanity/src/core/store/_legacy/authStore/types.ts 0% 0% 0% 0%
packages/sanity/src/core/studio/AuthBoundary.tsx 39.16% 30.76% 33.33% 55.73% 30, 42-45, 47, 53-56, 69, 75, 77-79, 91-92, 95, 97-98, 102, 102-108, 111-39, 40-135
Generated in workflow #54186 for commit c259f04 by the Vitest Coverage Report Action

@bjoerge bjoerge self-requested a review March 31, 2026 13:30
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.

1 participant