Skip to content

Implementation for SEP-2350 Client-side scope accumulation in step-up authorization#1591

Open
mikekistler wants to merge 4 commits into
mainfrom
mdk/sep-2350
Open

Implementation for SEP-2350 Client-side scope accumulation in step-up authorization#1591
mikekistler wants to merge 4 commits into
mainfrom
mdk/sep-2350

Conversation

@mikekistler
Copy link
Copy Markdown
Contributor

Motivation and Context

Implements SEP-2350 client-side scope accumulation for step-up authorization in the C# SDK OAuth client flow.

Fixes: #1547

What changed

Runtime behavior

  • Updated ClientOAuthProvider to accumulate scopes across re-authorization attempts.
  • On 403 insufficient_scope, the next authorization request now sends the union of:
  • previously requested/granted scopes, and
  • newly challenged scopes from WWW-Authenticate.
  • This prevents losing previously granted permissions during step-up flows.

Thread-safety fix

  • Made the scope accumulator in ClientOAuthProvider thread-safe by protecting mutable scope state with a lock.

Documentation/comments

  • Updated internal auth metadata documentation to reflect SEP-2350 semantics:
  • challenge scopes are authoritative for the current operation,
  • clients should include prior scopes when re-authorizing.

Tests

Updated and added OAuth tests in ModelContextProtocol.AspNetCore.Tests:

  • Updated existing step-up test to validate accumulated scope behavior.
  • Added a new multi-step test to verify scope accumulation across multiple step-up challenges.

All OAuth tests pass across net8.0/net9.0/net10.0 in this branch.

How Has This Been Tested?

Ran auth/scope-step-up against modelcontextprotocol/conformance main (branch install).

  • SEP-2350 check sep-2350-scope-union-on-reauth: SUCCESS
  • Scenario had one unrelated failure (sep-837-application-type-present), but SEP-2350 behavior passes.

Breaking Changes

None.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

mikekistler and others added 3 commits May 19, 2026 16:12
…zation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements SEP-2350 step-up authorization behavior in the C# SDK OAuth client flow by accumulating requested scopes across re-authorization attempts, and updates tests/docs to validate and describe the new semantics.

Changes:

  • Updated ClientOAuthProvider to union previously requested scopes with newly challenged scopes (and added locking for thread-safety).
  • Updated OAuth step-up tests to validate scope accumulation across one and multiple 403 insufficient_scope challenges.
  • Added internal documentation updates (PRM metadata semantics) and a new “run conformance from branch” skill guide.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthTests.cs Expands step-up OAuth tests to validate accumulated scopes across multiple authorization challenges.
src/ModelContextProtocol.Core/Authentication/ProtectedResourceMetadata.cs Updates internal PRM documentation to describe SEP-2350 scope accumulation expectations.
src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs Implements scope accumulation (union) and adds locking around mutable scope state.
.github/skills/run-conformance-from-branch/SKILL.md Adds workflow documentation for running conformance tests against a GitHub branch build.

Comment on lines +752 to +756
_previouslyRequestedScopes.Add(scope);
}

return string.Join(" ", _previouslyRequestedScopes);
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot are scopes ordered? Is this a correctness concern or just a concern about possible flaky tests that don't treat scopes as unordered?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OAuth scopes are not ordered — per RFC 6749 §3.3 they're a space-delimited set, so the server treats them as a set regardless of order. This is not a correctness concern for the OAuth protocol.

It is, however, a real flaky test concern: the AuthorizationFlow_UsesScopeFromProtectedResourceMetadata test was asserting an exact scope string ("mcp:tools files:read") that could fail nondeterministically since HashSet enumeration order is not guaranteed.

Fixed in 84b5585 by:

  • Sorting scopes with OrderBy(s => s, StringComparer.Ordinal) before joining in GetScopeParameter, so the emitted scope parameter is stable and deterministic.
  • Updating the one test that used an exact string assertion to use an order-independent HashSet comparison (consistent with the pattern already used in the other scope tests).


Return repo to pinned dependency state:

```bash
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SEP-2350: Clarify client-side scope accumulation in step-up authorization

3 participants