Skip to content

feat: add multi-level initial access token support for OAuth 2.0 Dynamic Client Registration (RFC 7591) #773

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

andormarkus
Copy link

@andormarkus andormarkus commented Jul 16, 2025

Summary

Implements multi-level initial access token support for OAuth 2.0 Dynamic Client Registration according to RFC 7591. This enables clients to register with authorization servers that require pre-authorization for dynamic client registration.

Changes

Core Implementation

  • Extended OAuthClientProvider interface with optional initialAccessToken() method
  • Enhanced registerClient() function with multi-level fallback logic
  • Updated transport layers (StreamableHTTP & SSE) to support initial access tokens
  • RFC 7591 compliant - adds Authorization: Bearer <token> header when token available

Multi-Level Fallback Priority

  1. Explicit parameter (highest priority) - passed directly to registerClient()
  2. Provider method - via OAuthClientProvider.initialAccessToken()
  3. Environment variable - OAUTH_INITIAL_ACCESS_TOKEN
  4. None - existing behavior (backward compatible)

Usage Examples

Transport-Level Configuration

const transport = new StreamableHTTPClientTransport(serverUrl, {
  authProvider: provider,
  initialAccessToken: "your-initial-token"
});

Provider-Level Configuration

class MyOAuthProvider implements OAuthClientProvider {
  async initialAccessToken(): Promise<string | undefined> {
    return await this.loadFromSecureStorage();
  }
  // ... other required methods
}

Environment Variable

export OAUTH_INITIAL_ACCESS_TOKEN="your-initial-token"

Testing

  • 10 new comprehensive tests covering all fallback levels
  • Full test suite passes (657 tests across 33 suites)
  • Backward compatibility maintained
  • RFC 7591 compliance verified

Breaking Changes

None - this is a fully backward-compatible addition.

Related

…mic Client Registration (RFC 7591)

- Extend OAuthClientProvider interface with optional initialAccessToken() method
- Update registerClient() to support multi-level fallback:
  1. Explicit parameter (highest priority)
  2. Provider method
  3. OAUTH_INITIAL_ACCESS_TOKEN environment variable
  4. None (existing behavior)
- Add initialAccessToken option to StreamableHTTPClientTransport and SSEClientTransport
- Update auth flow to pass initial access token through all transport layers
- Add Authorization: Bearer header to registration requests when token available
- Add comprehensive test coverage for all fallback levels
- Maintain backward compatibility with servers not requiring pre-authorization

Implements RFC 7591 specification for OAuth 2.0 Dynamic Client Registration
with initial access tokens for authorization servers requiring pre-authorization.
IDE-specific files should not be committed to the repository
…mic Client Registration (RFC 7591)

- Extend OAuthClientProvider interface with optional initialAccessToken() method
- Update registerClient() to support multi-level fallback:
  1. Explicit parameter (highest priority)
  2. Provider method
  3. OAUTH_INITIAL_ACCESS_TOKEN environment variable
  4. None (existing behavior)
- Add initialAccessToken option to StreamableHTTPClientTransport and SSEClientTransport
- Update auth flow to pass initial access token through all transport layers
- Add Authorization: Bearer header to registration requests when token available
- Add comprehensive test coverage for all fallback levels
- Add detailed OAuth client configuration documentation
- Maintain backward compatibility with servers not requiring pre-authorization

Implements RFC 7591 specification for OAuth 2.0 Dynamic Client Registration
with initial access tokens for authorization servers requiring pre-authorization.
@ihrpr ihrpr requested review from a team and pcarleton and removed request for a team July 18, 2025 13:16
@ihrpr ihrpr added this to the auth milestone Jul 22, 2025
Copy link
Contributor

@pcarleton pcarleton left a comment

Choose a reason for hiding this comment

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

Hi,

Generally on-board with supporting this, and appreciate that this is following the RFC:
https://www.rfc-editor.org/rfc/rfc7591.html#section-3.1

The RFC uses the term "initial access token", but informally, and related just to DCR. In this SDK, we'll need to call the token something like "DCR_REGISTRATION_ACCESS_TOKEN" or similar.

Also, I don't think we want 3 levels of fallback. Users can implement their own OAuthProvider, and that provider can fallback to parameters or environment variables, but this is a relatively narrow use case so I don't think it warrants having special handling code in all the different places. (i.e. the single appropriate place I see is in the auth.ts and by calling an optional function on the OAuthProvider).

- Rename OAuthClientProvider.initialAccessToken() to dcrRegistrationAccessToken()
- Update environment variable from OAUTH_INITIAL_ACCESS_TOKEN to DCR_REGISTRATION_ACCESS_TOKEN
- Update all documentation and comments to use DCR terminology
- Add clarifications that RFC 7591 calls this "initial access token"
- Maintains RFC 7591 compliance while using more specific SDK terminology

Addresses PR feedback to use clearer naming for Dynamic Client Registration tokens.
BREAKING CHANGE: Removed initialAccessToken parameters from transport constructors

- Rename initialAccessToken() to dcrRegistrationAccessToken() in OAuthClientProvider
- Remove 3-level fallback complexity per PR feedback
- Consolidate DCR token logic in auth.ts with resolveDcrToken() helper
- Remove initialAccessToken options from StreamableHTTP and SSE transports
- Keep environment variable DCR_REGISTRATION_ACCESS_TOKEN as automatic fallback
- Update all documentation to use DCR terminology with RFC 7591 clarifications
- Update tests to reflect new 2-level approach: provider method → env var
- Users can implement custom fallback logic in their OAuthProvider

Addresses PR feedback: "I don't think we want 3 levels of fallback. Users can
implement their own OAuthProvider, and that provider can fallback to parameters
or environment variables, but this is a relatively narrow use case so I don't
think it warrants having special handling code in all the different places."

RFC 7591 compliance maintained. Environment variable support preserved for convenience.
…ess token)

Add comprehensive support for DCR registration access tokens (called "initial access token" in RFC 7591) for OAuth 2.0 Dynamic Client Registration. This enables pre-authorization for client registration with authorization servers that require it.

Features:
- Optional `dcrRegistrationAccessToken()` method in OAuthClientProvider interface
- Clean 2-level fallback: provider method → DCR_REGISTRATION_ACCESS_TOKEN env var → none
- Automatic integration with existing registerClient() function
- Comprehensive test coverage with all fallback scenarios
- Enhanced examples demonstrating basic and advanced DCR strategies

Examples:
- Updated simpleOAuthClient.ts with DCR token demonstration
- New advancedDcrOAuthClient.ts showing production-ready strategies
- Support for CLI arguments, environment variables, and secure storage
- Complete documentation with RFC 7591 terminology mapping

Implementation follows feedback to:
- Use descriptive naming (DCR_REGISTRATION_ACCESS_TOKEN vs generic "initial access token")
- Implement clean 2-level fallback without excessive complexity
- Place token handling specifically in auth.ts registerClient function
- Maintain backward compatibility

Resolves: Support for RFC 7591 Dynamic Client Registration initial access tokens"
@andormarkus andormarkus requested review from a team as code owners July 24, 2025 17:19
@andormarkus andormarkus requested review from ochafik and ihrpr July 24, 2025 17:19
@andormarkus
Copy link
Author

Hi @pcarleton !

Thank you for the thoughtful feedback! I really appreciate the guidance on the RFC 7591 implementation approach.

I've implemented all the suggestions you mentioned:

Naming Convention: Used DCR_REGISTRATION_ACCESS_TOKEN throughout instead of the generic "initial access token" terminology, while maintaining clear documentation references to RFC 7591 for users familiar with the spec.

Simplified Fallback: Implemented a clean 2-level fallback approach exactly as suggested:

  1. Optional dcrRegistrationAccessToken() method on OAuthProvider (if implemented)
  2. DCR_REGISTRATION_ACCESS_TOKEN environment variable (automatic fallback)
  3. Proceed without token (for servers that don't require pre-authorization)

Proper Integration: The implementation is contained specifically in auth.ts within the registerClient() function, with an optional method call to the OAuthProvider as recommended.

I've also added comprehensive test coverage for all fallback scenarios and created detailed examples showing both basic usage and advanced production strategies (including secure storage integration, token exchange patterns, etc.). The documentation clearly maps our SDK naming to the RFC 7591 terminology so users can easily find this functionality.

The implementation maintains full backward compatibility and follows the principle of keeping the core simple while allowing users to implement sophisticated custom logic in their OAuthProvider if needed.

Thanks again for the excellent guidance - this approach feels much cleaner and more maintainable!

* Internal helper to resolve DCR registration access token from provider and environment.
* Implements a clean 2-level fallback: provider method → environment variable.
*/
async function resolveDcrToken(provider?: OAuthClientProvider): Promise<string | undefined> {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we should have the fallback, if you want to have the fallback to the environment variable in your Provider implementation, that's okay, but it doesn't need to be in the main flow.

Copy link
Author

Choose a reason for hiding this comment

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

Hi!

Great point about the fallback design! Let me explain the reasoning behind including the environment variable fallback in the main SDK flow.

The key benefit is ecosystem-wide DCR support without additional implementation burden. Any project that uses this SDK (like MCP Inspector, or any other tooling built on the SDK) would automatically get DCR token support simply by setting DCR_REGISTRATION_ACCESS_TOKEN - no code changes required.

If we move the environment variable fallback to only the Provider implementation:

  • ✅ Cleaner separation of concerns in the SDK
  • ❌ Every downstream project needs to implement their own env var handling
  • ❌ Fragmented DCR support across the ecosystem (some tools support it, others don't)
  • ❌ More boilerplate for simple use cases

The current approach means:

  • Universal DCR support: All SDK-based tools get DCR token support for free
  • Zero-config experience: Just set the env var and it works everywhere
  • Custom logic still possible: Providers can implement sophisticated strategies via the dcrRegistrationAccessToken() method
  • Graceful degradation: No token = proceed normally

I think the ecosystem benefit of "set one env var, DCR works everywhere" outweighs the slight complexity in the SDK. It follows the principle of making simple things simple (env var) while keeping complex things possible (custom provider logic).

What are your thoughts on this trade-off? Happy to discuss alternative approaches that might achieve both goals!

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.

Add Initial Access Token Support for Dynamic Client Registration
4 participants