fix(console): stale browser token must not override the gateway; a dead deep link must fall back, not dead-end - #20
Open
damonleelcx wants to merge 1 commit into
Conversation
… and let a dead deep link fall back instead of dead-ending Two ways this page reported "session expired" when the session was fine. 1. Personal's composing gateway owns team authentication SERVER-side: it reads the current CLI JWT from the local vault and injects it into forwarded requests. A token in localStorage is stale by construction in that quadrant — `aikey login` refreshes the vault, not the browser — and was overriding the authoritative one. `shouldAttachBrowserToken` suppresses it for exactly two quadrants: Personal, and a gateway-forwarded Team page. Standalone Trial keeps the historical local_bypass behaviour, because its one server may use the browser token to resolve a real identity. 2. A vault deep link can outlive the group or account it targeted. Master rejects the stale credential with 403, which the page rendered as an expired team session. Now a scoped read that comes back `unauth` retries the caller's ordinary projection once; a genuinely expired JWT still fails the unscoped retry and stays `unauth`. On the page side, `isKnownPoolFilter` treats a SUCCESSFUL groups response as authoritative and drops both coupled deep-link fields (`group`, `expand`) from the URL, so a bad bookmark shows the caller's current projection instead of an empty dead end. Test: `tsc --noEmit` clean; `vitest run src/shared/api src/pages/user/oauth-contribute` → 14 files, 71 tests green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two independent ways this page reported "session expired" when the session was fine.
1 · A stale browser token overrode the gateway's authoritative one
Personal's composing gateway owns team authentication server-side: it reads the current CLI JWT from the local vault and injects it into forwarded requests. A token in
localStorageis stale by construction in that quadrant —aikey loginrefreshes the vault, not the browser.shouldAttachBrowserToken(newshared/api/browser-auth.ts) suppresses the browserAuthorizationheader for exactly two quadrants:local_bypass+ Personallocal_bypass+ Team via gatewaylocal_bypass+ standalone Trial2 · A stale deep link rendered as an expired session
A vault deep link can outlive the group or account it targeted. Master rejects the stale credential with 403, which the page rendered as an expired team session.
fetchMyPoolAccounts: a scoped read that returnsunauthretries the caller's ordinary projection once. A genuinely expired JWT still fails the unscoped retry and staysunauth.isKnownPoolFilter: a successful groups response is authoritative, so the page drops both coupled deep-link fields (group,expand) from the URL and shows the caller's current projection instead of an empty dead end.Test
Companion PRs: aikey-trial-server#10 (the gateway side of the same failure) and the matching
aikey-control-masterchange.🤖 Generated with Claude Code