Skip to content

fix(client): coalesce refresh consumers and drain rotation on logout - #441

Open
kartojal wants to merge 5 commits into
feat/dev-750-platform-api-keysfrom
feat/auth-refresh-coalescing
Open

kartojal wants to merge 5 commits into
feat/dev-750-platform-api-keysfrom
feat/auth-refresh-coalescing

Conversation

@kartojal

@kartojal kartojal commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Coalesces refresh consumers and keeps logout safe during token rotation, including retry backoff after an uncertain refresh outcome.

Fresh-token requests and late 401 recovery await the accepted shared rotation. Logout closes local consumers, retains the latest started rotation outcome for revocation, and does not adopt or persist logout-only credentials. A possibly consumed refresh token is not resubmitted. Valid-bearer revocation, cancellation isolation and deterministic timer cleanup are preserved.

Rebased onto #438, retaining automatic L2 migration, plain bearer credentials and signer-only restoration from #437. Resolved the logout documentation conflict without reintroducing obsolete L2-client behavior.

Inherits #437's setup-failure session revocation and deferred new-session credential notifications. The stack was rebased with regression coverage for routed wallet deployment failures and #441's rotation-aware logout.

Stack: #442 → #481 → #437 → #463 → #438 → #441.

Restacked on 2026-11-02 with the current retry/transport ancestry and #463 Gateway routing corrections. Existing plain bearer credentials, automatic migration and signer-only restoration are retained.

Combined stack validation on 2026-11-02: build, lint, workspace typecheck, browser bundle check, 415 bindings tests and 1,159 client tests passed (1,574 total, no type errors). Failure-path coverage uses controlled responses. Live production checks additionally passed for an existing Deposit Wallet: signed login, automatic saved-L2 migration without signing, authenticated order/trade/notification/trading-status/balance-allowance reads, bearer restoration/refresh, and logout with rejected refresh reuse. No trading, transfers, approvals or wallet deployment were performed.

Gateway heartbeat compatibility remains blocked as documented in #463. Human approval and outstanding review threads have not been resolved automatically.


Note

High Risk
Changes core session token rotation and logout semantics, including refresh-token reuse rules and race handling that affect every authenticated client lifecycle.

Overview
Auth session refresh and logout are tightened so concurrent callers share one rotation and logout stays safe when a refresh is in flight or in retry backoff.

ready() and recover() now join an active refresh (including while the access token is still fresh), and refresh() installs the shared promise before the refresh callback runs so synchronous re-entry cannot start a second rotation. Each network attempt is tracked via #refreshRequest so logout can await the in-flight result for revocation only—without adopting tokens, firing onCredentialsChanged, or re-submitting a refresh that may already have consumed the refresh token.

Logout closes local consumers immediately (#stop(false)) instead of aborting rotation up front, then chooses revoke vs one explicit refresh for expired_access_token based on whether further refresh is still allowed after uncertain or definite failures. close() still aborts in-flight renewal; closing before #renew runs skips the callback entirely.

The authentication migration doc logout section is updated to describe drain-on-logout, uncertain-outcome behavior, and immediate local shutdown. session.test.ts adds regression coverage for coalescing, logout drain, no replay during backoff/uncertainty, and revocation after a failed refresh attempt.

Reviewed by Cursor Bugbot for commit 791cf76. Bugbot is set up for automated code reviews on this repo. Configure here.

@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from ef9fbfd to d456640 Compare October 20, 2026 14:32
Base automatically changed from feat/auth-refresh-callback to feat/dev-750-platform-api-keys October 20, 2026 14:32
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from d456640 to 65cf711 Compare October 20, 2026 16:16
@kartojal
kartojal added this pull request to stack #443 October 20, 2026 16:27
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from 65cf711 to 6ee0888 Compare October 20, 2026 16:35
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch 2 times, most recently from a397b25 to d0a23a9 Compare October 21, 2026 08:17
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from d0a23a9 to 07d3c80 Compare October 21, 2026 08:52
@kartojal
kartojal marked this pull request as ready for review October 21, 2026 08:56
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from 07d3c80 to ec3d5ed Compare October 21, 2026 09:12
@kartojal kartojal mentioned this pull request Oct 21, 2026
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from ec3d5ed to fa3daee Compare October 22, 2026 11:21

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fa3daee. Configure here.

Comment thread packages/client/src/session.ts Resolved
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from 9f02b98 to 9e438da Compare October 22, 2026 15:28
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from 9e438da to eff16ac Compare October 22, 2026 17:03
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from eff16ac to 77fa5cc Compare October 23, 2026 12:08
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from 77fa5cc to 5bbed26 Compare October 23, 2026 13:19
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch 2 times, most recently from 51f2bcf to 5bbed26 Compare October 26, 2026 08:28
@kartojal
kartojal removed this pull request from stack #464 October 26, 2026 15:46
@kartojal
kartojal added this pull request to stack #482 October 26, 2026 15:47
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from 4af58a4 to 0711aa6 Compare October 27, 2026 17:54
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch 2 times, most recently from 79e3725 to 79af214 Compare November 2, 2026 16:55
Only network and 5xx refresh failures block a logout-only refresh; a rate limit or 4xx rejection leaves the refresh token unused, so logout refreshes once and revokes. Restore the refreshing guard, make the closed-session test meaningful, describe the outcome in the migration doc, and drop the internal changeset.
@kartojal
kartojal force-pushed the feat/auth-refresh-coalescing branch from 79af214 to 791cf76 Compare November 3, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant