[BUG] Claude Code doesn't use scope from WWW-Authenticate during step-up authorization

Resolved 💬 2 comments Opened Jan 18, 2026 by nrpeterson Closed Feb 27, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When an MCP server returns HTTP 403 with WWW-Authenticate: Bearer error="insufficient_scope", scope="graph:read", Claude Code initiates a new OAuth flow but does NOT include the indicated scope in its authorization request. This breaks the step-up authorization (upscoping) flow defined in the MCP Authorization spec.

What Should Happen?

Per MCP Authorization Spec Section 2.3.2:

  1. Client calls a tool with a valid token lacking required scopes
  2. Server returns 403 Forbidden with:

``
WWW-Authenticate: Bearer error="insufficient_scope", scope="graph:read", resource_metadata="..."
``

  1. Client extracts scope="graph:read" from the header
  2. Client initiates OAuth flow requesting graph:read (plus any existing scopes)
  3. User consents to the specific scope
  4. Client retries with new token containing graph:read

Error Messages/Logs

1. ✅ Calls tool with token containing `["openid", "offline_access"]`
2. ✅ Receives 403 with `scope="graph:read"` in WWW-Authenticate
3. ❌ Initiates OAuth flow but only requests `["offline_access", "offline", "openid"]`
4. ❌ New token still only has `["openid", "offline_access"]`
5. ❌ Retry fails with same 403

**The scope from the WWW-Authenticate header is not being parsed and used.**

Steps to Reproduce

  1. Configure an MCP server that:
  • Returns empty scopes_supported in /.well-known/oauth-protected-resource
  • Requires graph:read scope for a tool
  • Returns proper RFC 6750 WWW-Authenticate header on 403
  1. Connect Claude Code to the server (will auth with minimal scopes since none advertised)
  1. Call the protected tool
  1. Observe: Claude Code attempts upscoping but doesn't include the required scope

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.12 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

Server 403 Response

HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope", scope="graph:read", resource_metadata="http://mcp-graph.localhost/.well-known/oauth-protected-resource"
Content-Type: application/json

{"jsonrpc":"2.0","error":{"code":-32001,"message":"insufficient scope, need: graph:read"},"id":1}

Token Before Upscope Attempt

{
  "jti": "91e68349-2fc4-453a-919e-05a0af4a2e83",
  "scp": ["openid", "offline_access"]
}

OAuth Request During Upscope (from consent server logs)

Processing consent request
  client_id=61af3d8d-0615-46b4-bf81-615c45c66573
  requested_scopes=["offline_access", "offline", "openid"]  ← Missing graph:read!

Token After Upscope Attempt

{
  "jti": "d01145d3-a158-4e21-84d7-6bac4bfb607d",
  "scp": ["openid", "offline_access"]
}

Note: Different jti confirms a new token was issued, but scopes are identical.

Timeline from Logs

| Time | Event |
| ------------ | ----------------------------------------------------------- |
| 18:37:01.733 | Claude Code calls tools/call with token ...2e83 |
| 18:37:01.734 | Server returns 403 with scope="graph:read" |
| 18:37:01.740 | Claude Code fetches /.well-known/oauth-protected-resource |
| 18:37:01.839 | Claude Code retries with NEW token ...607d (same scopes) |
| 18:37:01.839 | Server returns 403 again (still no graph:read) |

Relevant Specifications

error="insufficient_scope"

  • RFC 9728 - OAuth 2.0 Protected Resource Metadata

Impact

This prevents the "principle of least privilege" flow where:

  • Clients start with minimal scopes
  • Scopes are requested on-demand when needed
  • Users consent to specific scopes for specific operations

Currently, the only workaround is to advertise all possible scopes in scopes_supported, which causes Claude Code to
request everything upfront, putting the burden on users to manually uncheck unwanted scopes.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗