Description
When a widget visitor is identified via SSO (e.g. Clerk) and their identified session token is stored only in JS memory, any page-level disruption (tab switch, focus loss, browser memory pressure, brief JS execution pause) clears the in-memory token. On the next form submission:
ensureSession() mints a fresh anonymous session (because only anonymous tokens are persisted to localStorage)
createPublicPostFn → requireAuth() resolves the anonymous principal
- With
portalConfig.features.allowAnonymous = false, the server throws "Anonymous interaction is not enabled"
- The widget catches this and displays the generic
"Network error. Please try again." — giving the user no indication that re-authentication would fix it
Steps to Reproduce
- Configure Quackback with
identifyVerification: true and allowAnonymous: false
- Embed the widget on a host page using Clerk SSO
- Identify via SSO — the widget shows the user as logged in
- Trigger a page disruption (switch tabs and return, or trigger browser memory pressure)
- Submit feedback on any board
- Observe: "Network error. Please try again."
Evidence
Server logs (production instance):
{"level":"error","component":"public-posts","route":"POST /_serverFn/3124a077...",
"err":{"message":"Anonymous interaction is not enabled"},"msg":"create public post failed"}
Root cause trace:
widget-auth.ts: persistAnonymousToken() exists, but no persistIdentifiedToken() — identified tokens are memory-only
widget-auth-provider.tsx: applyIdentifyResult() explicitly drops anonymous token but never persists the identified one
widget-auth-provider.tsx: acquireSession() only tries to restore anonymous persisted tokens, never identified ones
widget-home-animated.tsx: handleSubmit() falls through to ensureSession() (anonymous mint) when isIdentified is false
widget-home-animated.tsx: catch block swallows all errors as generic "Network error"
Database confirmation:
Verified a real user (name@gmail.com) who was properly identified (hmac_verified=true, principal.type=user) but has zero posts — her submission was rejected during the anonymous fallback.
Proposed Fix
Branch with fix: https://github.com/MrFreePress/quackback/tree/fix/widget-identified-session-loss
Three changes:
- Persist identified tokens to localStorage (
widget-auth.ts) — mirroring the existing anonymous token persistence
- Restore identified tokens on session acquisition (
widget-auth-provider.tsx) — try identified token before falling back to anonymous mint
- Better error message (
en.json + widget-home-animated.tsx) — surface "Your session has expired" instead of "Network error"
PR incoming.
Description
When a widget visitor is identified via SSO (e.g. Clerk) and their identified session token is stored only in JS memory, any page-level disruption (tab switch, focus loss, browser memory pressure, brief JS execution pause) clears the in-memory token. On the next form submission:
ensureSession()mints a fresh anonymous session (because only anonymous tokens are persisted to localStorage)createPublicPostFn→requireAuth()resolves the anonymous principalportalConfig.features.allowAnonymous = false, the server throws"Anonymous interaction is not enabled""Network error. Please try again."— giving the user no indication that re-authentication would fix itSteps to Reproduce
identifyVerification: trueandallowAnonymous: falseEvidence
Server logs (production instance):
Root cause trace:
widget-auth.ts:persistAnonymousToken()exists, but nopersistIdentifiedToken()— identified tokens are memory-onlywidget-auth-provider.tsx:applyIdentifyResult()explicitly drops anonymous token but never persists the identified onewidget-auth-provider.tsx:acquireSession()only tries to restore anonymous persisted tokens, never identified oneswidget-home-animated.tsx:handleSubmit()falls through toensureSession()(anonymous mint) whenisIdentifiedis falsewidget-home-animated.tsx: catch block swallows all errors as generic "Network error"Database confirmation:
Verified a real user (name@gmail.com) who was properly identified (hmac_verified=true, principal.type=user) but has zero posts — her submission was rejected during the anonymous fallback.
Proposed Fix
Branch with fix: https://github.com/MrFreePress/quackback/tree/fix/widget-identified-session-loss
Three changes:
widget-auth.ts) — mirroring the existing anonymous token persistencewidget-auth-provider.tsx) — try identified token before falling back to anonymous minten.json+widget-home-animated.tsx) — surface "Your session has expired" instead of "Network error"PR incoming.