fix(auth): preserve explicitly granted pairing scopes - #9785
fix(auth): preserve explicitly granted pairing scopes#9785juliusmarminge wants to merge 4 commits into
Conversation
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR changes production authentication and authorization behavior across server, browser, mobile, and shared client-runtime flows, including scope issuance and grant replacement. It also adds static-analysis suppression directives, so the sensitive runtime surface and review policy require human review. You can add or adjust custom eligibility rules. Learn more. |
6c5c74d to
d52b9a1
Compare
d52b9a1 to
fa5d32f
Compare
Clients request the full default scope set when pairing, which rejects deliberately limited grants. A rejected exchange can consume the pairing link, and an already-authenticated browser skips replacement pairing links.
Use the scopes granted by the pairing token across web, desktop, and mobile. Validate requested scopes before consuming a link, add repeatable
--scopeoptions to the pairing and session commands, and let an explicit browser pairing link replace the current grant. Successful browser pairing reloads the app to refresh its WebSocket credentials; a rejected token preserves the existing session and shows the error.Existing clients retain their current scopes until they pair again with a fresh grant. Reconnecting does not add permissions.
Tests added cover selected CLI scopes and persistence, rejected exchanges preserving a usable link, clients retaining custom grants, and browser replacement with cached authentication, query/hash tokens, and invalid-token recovery.
Model: GPT-6. Harness: Codex.
Note
High Risk
Changes authentication scope validation, pairing-link consumption, and how sessions are issued across server, CLI, and all clients—security-critical behavior with nuanced edge cases (browser re-pair, desktop bootstrap narrowing).
Overview
Fixes pairing and token exchange so clients inherit the scopes minted on the link instead of always requesting the full default set, which could reject limited grants and (previously) burn one-time tokens.
Server:
PairingGrantStore.consumeand pairing-link SQL consumption now accept optionalrequestedScopes, returnBootstrapCredentialScopeNotGrantedErrorwhen a requested scope exceeds the grant, and do not consume the link on that failure. Token exchange forwards requested scopes into consume and maps that error toServerAuthScopeNotGrantedError.CLI: Repeatable
--scopeont3 pair,t3 auth pairing create, andt3 auth session issue(defaults unchanged when omitted); invalid scopes fail at parse time.Clients: Web, mobile, and
client-runtimestop attaching fixed client scopes to presentation and OAuth exchange—omittingscopemeans “use the grant.”Browser: Visiting
/pairwith a token forces the pairing flow even if already authenticated; success reloads/to refresh WebSocket credentials; a bad replacement token keeps the existing session and stays on the pairing UI.Docs cover choosing scopes and replacing grants via a new link.
Reviewed by Cursor Bugbot for commit fa5d32f. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Preserve explicitly granted pairing scopes and add CLI
--scopeflagsPairingGrantStore.consumeso requesting ungranted scopes fails and leaves the credential available for later use.--scopeoptions to thet3 pair,auth pairing create, andauth session issueCLI commands, defaulting to standard client or administrative scopes.AuthStandardClientScopesfrom theClientPresentationcontract across mobile, web, and client-runtime so bootstrap grants dictate the authorized scopes./pairon an already authenticated browser.ClientPresentationservice contract no longer includes ascopesfield, breaking out-of-tree implementations that rely on it. Successful browser re-pairing now performs a full application reload viawindow.location.replaceinstead of a client-side router transition.Macroscope summarized fa5d32f.