Skip to content

Commit c231be9

Browse files
committed
auth: union scopes on 403 step-up (SEP-2350)
1 parent 61635c6 commit c231be9

1 file changed

Lines changed: 10 additions & 4 deletions

File tree

src/mcp/client/auth/oauth2.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
handle_token_response_scopes,
3636
is_valid_client_metadata_url,
3737
should_use_client_metadata_url,
38+
union_scopes,
3839
)
3940
from mcp.client.streamable_http import MCP_PROTOCOL_VERSION
4041
from mcp.shared.auth import (
@@ -624,20 +625,25 @@ async def async_auth_flow(self, request: httpx.Request) -> AsyncGenerator[httpx.
624625
error = extract_field_from_www_auth(response, "error")
625626

626627
# Step 2: Check if we need to step-up authorization
627-
if error == "insufficient_scope": # pragma: no branch
628+
if error == "insufficient_scope":
628629
try:
629-
# Step 2a: Update the required scopes
630-
self.context.client_metadata.scope = get_client_metadata_scopes(
630+
# Step 2a: Union previously requested scopes with the
631+
# step-up challenge so prior grants survive (SEP-2350).
632+
challenge_scopes = get_client_metadata_scopes(
631633
extract_scope_from_www_auth(response),
632634
self.context.protected_resource_metadata,
633635
self.context.oauth_metadata,
634636
self.context.client_metadata.grant_types,
635637
)
638+
self.context.client_metadata.scope = union_scopes(
639+
self.context.client_metadata.scope,
640+
challenge_scopes,
641+
)
636642

637643
# Step 2b: Perform (re-)authorization and token exchange
638644
token_response = yield await self._perform_authorization()
639645
await self._handle_token_response(token_response)
640-
except Exception: # pragma: no cover
646+
except Exception:
641647
logger.exception("OAuth flow error")
642648
raise
643649

0 commit comments

Comments
 (0)