SEP-2350: accumulate scopes on step-up auth#2676
Open
dogacancolak wants to merge 3 commits into
Open
Conversation
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.
Implements MCP spec PR #2350 (closes #2349): on a
403 insufficient_scopestep-up challenge, the client now unions the challenge scopes with its previously-requested scope set instead of replacing them. Stateless servers can now emit per-operationWWW-Authenticatechallenges (the spec-recommended posture) without forcing the client to drop prior grants on every step-up.Motivation and Context
The previous spec told servers to include "previously granted scopes" in
insufficient_scopechallenges, conflicting with RFC 6750 §3.1. The amended spec moves accumulation to the client.The SDK was replacing
client_metadata.scopewith the challenge scopes, so a client doingread→write→adminoperations would lose prior scopes on each step-up and trigger re-auth loops.What changed
src/mcp/client/auth/oauth2.pynow callsunion_scopes(client_metadata.scope, challenge_scopes)instead of overwriting. The 401 branch is unchanged (replace semantics) — full re-login remains the natural down-scoping opportunity.client_metadata.scope(what we requested last time), notcurrent_tokens.scope(what the AS granted). If the AS narrowed the grant at consent time, we still re-request the broader set on the next step-up rather than silently dropping scopes the user previously declined.Behavior
readrequested → 403scope="write"→ re-auth withread write.read writerequested, grantedreadonly → 403scope="delete"→ re-auth withread write delete(write survives the narrow grant).Tests
Unit tests for
union_scopes.End-to-end tests driving
async_auth_flowcover the entire step-up branch, not just the union behavior:read→ step-up addswrite→ step-up addsadminends withread write admin, not justadmin.read write adminbut the AS only grantedread writeat consent, a later step-up fordeletere-authorizes withread write admin delete— the declinedadminis re-requested rather than silently dropped.insufficient-scopedoes not trigger re-auth.read write adminwith the initial auth handshake's narrowerread. Pins the invariant so a future "let's union on 401 too" change fails loudly.Limitations / follow-ups
refresh_tokenflow itself.