Skip to content

Auth: idempotent refresh to close the tab-death cross-tab residual (#169 follow-up) #176

Description

@mforce

Context

Follow-up from the #169 (PR #175) review (codex). #169 serialises refresh across tabs with the Web Locks API, which eliminates the common multi-tab race. One narrow residual remains that a page-owned lock cannot close:

Tab A acquires the lock and sends refresh token R0. The server commits R0→R1 and sets the rotated cookie, but Tab A is closed/reloaded in the sub-second before the response + Set-Cookie are processed. Unloading auto-releases the Web Lock while the cookie is still R0. Tab B then acquires the lock, presents R0 (now revoked), and trips reuse-detection → whole-family revocation → both tabs logged out.

A lock held by a page cannot make server rotation and cookie receipt atomic, so the client alone cannot fully close this.

Proposed fix (server-side)

Make refresh idempotent for a short window: the client sends a stable per-exchange request id (or the server keys on the presented token + its immediate replacement). A repeat of the same exchange returns the same replacement instead of being treated as a replay, while an unrelated old/stolen token still trips strict reuse-detection.

Acceptance

  • A tab closed mid-refresh does not cause the next tab to be logged out.
  • A genuinely replayed/stolen (non-matching) token still revokes the family.
  • Tests cover the mid-refresh-tab-death sequence.

Referenced from a code comment in web/src/api/client.ts (#169).

Activity

  1. added 3 commits that reference this issue on Jul 24, 2026
    a50b8e8
    0806072
    683bb8f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions