Skip to content

feat: renew browser sessions with refresh tokens - #74

Draft
AntTheLimey wants to merge 5 commits into
feat/browser-loginfrom
feat/browser-login-refresh
Draft

AntTheLimey wants to merge 5 commits into
feat/browser-loginfrom
feat/browser-login-refresh

Conversation

@AntTheLimey

Copy link
Copy Markdown
Member

What changed

Step 2 of browser sign-in, stacked on #73. It removes the forced re-login when the access token expires.

  • Login requests offline_access and keeps Auth0's refresh token in the OS keychain, under its own entry, never in the config file or token cache. With no refresh token (until saas#2043 is applied) or no keychain, login behaves exactly as in feat: browser sign-in for pgedge starfleet #73.
  • Renewal happens when a session is near expiry, at first use or mid --wait. The rotated refresh token is saved before the new access token is cached and used. A per-profile lock file serialises renewal across processes. Under the lock, the cache is re-read so a second process uses the first one's renewal instead of reusing a rotated token, which Auth0 would treat as theft and revoke. saas#2043 also adds a 10s reuse leeway.
  • A refused renewal (invalid_grant) clears the refresh token, but only if it's still the one sent, and gives the existing exit-5 "sign in again" message. A network or 5xx failure keeps the token and falls back to the current access token while it's valid.
  • Logout revokes the refresh token at Auth0 (best-effort), then clears it. A refresh token that a new login or an API-client login replaces is revoked too.
  • auth status and doctor report whether a session renews. An expired access token with a refresh token is "renews on next use", exit 0.
  • --debug masks the refresh token, the token responses and the revoke token field.
  • Docs, llms pages and the starfleet skill say a session renews while in use and ends after a period without use or a fixed maximum.

Checks

  • make test passes. Coverage is 90.0% against the 90.0% threshold. make lint, make docs-check and make lint-docs are clean.
  • 4 new test functions: rotation order, refused renewal, logout revoke, and two concurrent renewals against a stub Auth0 that treats reuse as theft. Four existing tests were extended.
  • Mutation checks, all caught:
    • no rotated save
    • no access-token cache
    • token kept after invalid_grant
    • flag path clearing the session
    • lock removed
    • re-read removed
    • cache written before the keychain
  • One independent review: 1 Important finding (concurrent renewal wiping the session) and 4 Minor, all fixed here.

Risks

  • Coverage sits exactly at the threshold, so the next change that lowers it fails make test.
  • The stale-lock takeover after a crash is untested. The lock is taken over after 45s and waiters give up after 50s.
  • Nothing has run against a real Auth0. The dev test comes after saas#2040 and saas#2043 are applied.

@AntTheLimey
AntTheLimey force-pushed the feat/browser-login-refresh branch from eebf054 to 1b10de8 Compare October 19, 2026 22:09
Login asks for offline_access and keeps Auth0's refresh token in the
OS keychain. A session near expiry renews itself, saving the new access
token and the rotated refresh token before use. invalid_grant clears
the refresh token and ends the session; logout revokes it. Without a
refresh token or a keychain, step-1 behaviour is unchanged.
A per-profile lock file beside the token cache serialises renewal,
and the cache is re-read under it, so concurrent commands send the
rotating refresh token once. invalid_grant deletes the keychain entry
only if it still holds the token sent. The rotated refresh token is
saved before the access token; a transient renewal failure keeps
using a still-valid token. Discarded refresh tokens are revoked at
login, and doctor says why it skipped the Tenant row.
Cover the per-profile session lock and stale-lock recovery, the
refresh token keychain entry kept apart from the client secret, the
Auth0 refresh and revoke calls, and a refused or unreachable renewal
ending in exit 5.
@AntTheLimey
AntTheLimey force-pushed the feat/browser-login-refresh branch from 1b10de8 to 9385f9d Compare October 19, 2026 23:01
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