Skip to content

Bug: Identified widget session tokens lost on page disruption, causing 'Network error' on submit #331

Description

@MrFreePress

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:

  1. ensureSession() mints a fresh anonymous session (because only anonymous tokens are persisted to localStorage)
  2. createPublicPostFnrequireAuth() resolves the anonymous principal
  3. With portalConfig.features.allowAnonymous = false, the server throws "Anonymous interaction is not enabled"
  4. 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

  1. Configure Quackback with identifyVerification: true and allowAnonymous: false
  2. Embed the widget on a host page using Clerk SSO
  3. Identify via SSO — the widget shows the user as logged in
  4. Trigger a page disruption (switch tabs and return, or trigger browser memory pressure)
  5. Submit feedback on any board
  6. 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:

  1. Persist identified tokens to localStorage (widget-auth.ts) — mirroring the existing anonymous token persistence
  2. Restore identified tokens on session acquisition (widget-auth-provider.tsx) — try identified token before falling back to anonymous mint
  3. Better error message (en.json + widget-home-animated.tsx) — surface "Your session has expired" instead of "Network error"

PR incoming.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions