fix(auth): server-set fallback for cross-subdomain cookies#336
Open
rabble wants to merge 1 commit into
Open
Conversation
Adds a same-origin POST/DELETE /api/auth/persist-cookie endpoint in the divine-web Fastly Compute worker that emits Set-Cookie with Domain=.divine.video. document.cookie writes can silently fail in some privacy-hardened browsers (Brave, Firefox ETP-Strict, Safari ITP edge cases); browsers handle response Set-Cookie far more reliably. Decouples useDivineSession.clearSession() from clearJwtCookie() so that automatic JWT expiry on one subdomain no longer wipes the cross-subdomain cookie that backs every other subdomain's hydration. Only explicit user logout (AccountSwitcher) clears the cookie now. Adds diagnostic console.info in hydrateLoginFromCookie so the next report makes the failure mode visible at a glance. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying divine-web with
|
| Latest commit: |
eb67f29
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://eb7609d3.divine-web.pages.dev |
| Branch Preview URL: | https://fix-auth-server-set-cookie.divine-web.pages.dev |
🚀 Preview Deployment
|
DSanich
approved these changes
May 6, 2026
| @@ -1 +1 @@ | |||
| import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; | |||
Contributor
There was a problem hiding this comment.
Suggested change
| import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from 'vitest'; |
| }); | ||
| } | ||
|
|
||
| let fetchMock: ReturnType<typeof vi.fn>; |
Contributor
There was a problem hiding this comment.
ReturnType is a generic utility and must be given a type argument (for example ReturnType). As written, this is invalid in strict TypeScript and is easy to break silently if TS settings change. Please use ReturnType or Vitest’s Mock type for fetchMock.
Suggested change
| let fetchMock: ReturnType<typeof vi.fn>; | |
| let fetchMock: Mock; |
| */ | ||
| export function hydrateLoginFromCookie(): void { | ||
| const STORAGE_KEY = 'nostr:login'; | ||
| const log = (...args: unknown[]) => console.info('[crossSubdomainAuth]', ...args); |
Contributor
There was a problem hiding this comment.
These console.info calls will run for all users on every hydration path and may be noisy in production. Consider gating behind import.meta.env.DEV, a debug flag, or logging only once per session to keep diagnostics without polluting end-user consoles.
Suggested change
| const log = (...args: unknown[]) => console.info('[crossSubdomainAuth]', ...args); | |
| const log = (...args: unknown[]) => { | |
| if (import.meta.env.DEV) console.info('[crossSubdomainAuth]', ...args); | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Logins on
divine.videoweren't carrying over tousername.divine.videosubdomains. Root cause:document.cookiewrites silently fail in some browsers (Brave, Firefox ETP-Strict, Safari ITP edge cases) — the cookie looks set but the browser drops it.POST/DELETE /api/auth/persist-cookieto the Fastly Compute worker. Server emitsSet-Cookie: …; Domain=.divine.videowhich browsers honor far more reliably than client-side writes.useDivineSession.clearSession()fromclearJwtCookie(). A JWT expiry on one subdomain no longer wipes the cross-subdomain cookie that other subdomains hydrate from. Only explicit logout (AccountSwitcher) clears it.console.infoinhydrateLoginFromCookieso the next failure mode is visible at a glance.Test plan
vitest— 44 tests acrosscrossSubdomainAuth.test.ts,authPersistCookie.test.ts,AccountSwitcher.test.tsxpassdivine.video, confirm session appears on*.divine.video🤖 Generated with Claude Code