Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

OAuth: 403 responses without insufficient_scope incorrectly retry with same token #1602

Copy link
Copy link
@maxisbey

Description

@maxisbey
Issue body actions

Summary

The OAuth client unconditionally retries all 403 responses, even when the error is not insufficient_scope. This causes an unnecessary retry attempt with the same token that will fail for the same reason.

Location

src/mcp/client/auth/oauth2.py, lines 662-681

The Bug

elif response.status_code == 403:
    error = self._extract_field_from_www_auth(response, "error")
    
    # Only performs step-up if error == "insufficient_scope"
    if error == "insufficient_scope":
        self._select_scopes(response)
        token_response = yield await self._perform_authorization()
        await self._handle_token_response(token_response)
    
    # BUG: Retries unconditionally, even when no new tokens were obtained
    self._add_auth_header(request)
    yield request

Lines 679-681 execute regardless of whether step-up authorization occurred, causing a retry with the same credentials.

Expected vs Actual Behavior

Scenario Expected Actual
403 with insufficient_scope Get new tokens → retry ✅ Correct
403 with different error (e.g., invalid_token) Raise error immediately ❌ Retries once with same token, then fails
403 with no error field Raise error immediately ❌ Retries once with same token, then fails

Impact

  • Wasted network round-trip: Client makes doomed retry request that will fail for the same reason
  • Poor error feedback: Delays error reporting by one request cycle
  • Spec non-compliance: MCP Authorization Spec implies retry only for insufficient_scope
  • Resource waste: Unnecessary load on server and client

Fix

Move the retry logic inside the if error == "insufficient_scope": block and raise an error otherwise:

elif response.status_code == 403:
    error = self._extract_field_from_www_auth(response, "error")
    
    if error == "insufficient_scope":
        try:
            self._select_scopes(response)
            token_response = yield await self._perform_authorization()
            await self._handle_token_response(token_response)
            
            # Retry with new tokens
            self._add_auth_header(request)
            yield request
        except Exception:
            logger.exception("OAuth flow error")
            raise
    else:
        # Permanent authorization failure - cannot be resolved by retry
        raise OAuthFlowError(
            f"Access forbidden: {error or 'insufficient permissions'}"
        )

References


Authored by Claude, reviewed by @maxisbey

Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Nice to haves, rare edge casesNice to haves, rare edge casesauthIssues and PRs related to Authentication / OAuthIssues and PRs related to Authentication / OAuth

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.