Skip to content

fix(seedless-onboarding-controller): enhance token management with server-rotated tokens - #11344

Draft
tuna1207 wants to merge 2 commits into
mainfrom
fix/rotated-tokens-from-refresh
Draft

tuna1207 wants to merge 2 commits into
mainfrom
fix/rotated-tokens-from-refresh

Conversation

@tuna1207

@tuna1207 tuna1207 commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Explanation

auth-service is moving to one-time-use refresh tokens with family revocation (EMBED-529). A refresh now consumes the presented token and returns its successor (refresh_token and revoke_token). The controller must persist that successor, or the next renew/revoke will present a consumed token, the server will treat it as theft, and the user will be logged out.

This ships the core change so clients can release ahead of the server deploy.

  • RefreshJWTToken now optionally returns refreshToken and revokeToken. The fields stay optional so a new client still works against the old server during rollout.
  • #doRefreshAuthTokens persists the returned pair before any fallible work:
    • state.refreshToken and a persisted pendingRevokeToken are written first, so the successor is not lost if re-authentication or the vault write fails.
    • When the wallet is unlocked, the revoke token is written to the vault and pendingRevokeToken is cleared.
    • When the wallet is locked, pendingRevokeToken is kept and merged into the vault on the next unlock.
    • The server already rotated, so renew and revoke queuing are skipped.
  • pendingRevokeToken added to state with persist: true (not logged, not in debug snapshots, not in the UI).
  • rotateRefreshToken() prefers the pending successor token and clears it after persisting the renewed pair. It still renews, but no longer queues the consumed pair once the server is known to rotate.
  • authenticate() clears any pending token from the previous session, so a fresh login cannot mix token pairs.
  • clearState() and successful fresh authentication reset the in-memory rotation flag.

Backward compatibility

The old-server path is unchanged: when the refresh response has no new tokens, the controller updates the vault, calls rotateRefreshToken(), and queues the old pair for revocation as before. New state is optional, so no migration is needed.

Known limitation

#serverRotatesRefreshTokens is an in-memory flag and resets on restart. Until auth-service rotation is deployed everywhere, a standalone rotateRefreshToken() before the first refresh after a restart can still queue a consumed pair. Tracked in code with a shortcut: comment.

Follow-ups (other repos)

  • Extension and mobile OAuthService must map refresh_token and revoke_token from the /api/v1/oauth/token refresh response. Without it, the core change is inert.
  • Rollout order: ship clients, wait for adoption, then deploy auth-service rotation.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

…rver-rotated tokens

- Added optional `refreshToken` and `revokeToken` results to `RefreshJWTToken`, along with a persisted `pendingRevokeToken` state for deferred vault writes.
- Updated logic to persist refresh and revoke tokens even when the vault is locked, ensuring tokens are managed correctly without unnecessary renewals or revocations.
- Introduced tests to validate the new behavior of token persistence and state management during various controller operations.

This update improves the handling of authentication tokens, particularly in scenarios where server-side token rotation occurs, enhancing overall security and user experience.

This branch has not been deployed

No deployments
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