Skip to content

Implement MCP OAuth 2.1 Specification Compliance #73

@avrabe

Description

@avrabe

Problem

Our mcp-auth crate (17,480 lines) implements a custom API key-based authentication system that is not compliant with the official MCP specification. The MCP spec mandates OAuth 2.1 with PKCE for HTTP transports.

What We Have (Non-Standard)

  • ❌ Custom API key system (~3,150 lines: manager.rs + storage.rs)
  • ❌ Custom JWT session tokens (1,374 lines)
  • ❌ Custom auth extractors for HTTP/WebSocket/Stdio
  • ✅ RBAC (permissions) - could map to OAuth scopes
  • ✅ Transport abstractions - could be reused

What MCP Spec Requires

Per MCP Authorization Spec:

For HTTP Transports:

  • ✅ OAuth 2.1 (draft-ietf-oauth-v2-1-13) with PKCE
  • ✅ OAuth 2.0 Authorization Server Metadata (RFC 8414)
  • ✅ Dynamic Client Registration (RFC 7591)
  • ✅ Protected Resource Metadata (RFC 9728)
  • ✅ Resource Parameter Binding (RFC 8707)
  • ✅ Bearer token validation
  • ✅ Proper scope management (progressive, least-privilege)

For Stdio Transports:

  • ✅ Environment variable credential retrieval (we already have this)

Proposed Solution

Phase 1: Research & Design

  1. Evaluate Rust OAuth libraries:
    • oxide-auth - OAuth 2.0 server/client
    • oauth2 crate - Client-side OAuth flows
    • Custom implementation vs. existing crates
  2. Design architecture:
    • OAuth server endpoints (authorize, token, metadata)
    • PKCE implementation
    • Dynamic client registration
    • Token validation middleware
  3. Map existing features to OAuth:
    • RBAC permissions → OAuth scopes
    • Sessions → OAuth refresh tokens
    • API keys → Initial OAuth tokens (migration path)

Phase 2: Implement OAuth 2.1 Server

New modules to create:

mcp-auth/src/oauth/
├── mod.rs              # Public API
├── server.rs           # Authorization server
├── pkce.rs             # PKCE verification
├── client_registry.rs  # Dynamic client registration (RFC 7591)
├── token.rs            # Token generation/validation
├── metadata.rs         # Server metadata (RFC 8414)
├── resource.rs         # Resource metadata (RFC 9728)
└── scopes.rs           # Scope management

Estimated: ~2,500-3,500 lines

Phase 3: Delete/Replace Custom Auth

Delete:

  • manager.rs API key logic (~1,451 lines)
  • storage.rs API key storage (~1,699 lines)
  • Custom auth extractors that don't use OAuth

Keep/Adapt:

  • jwt.rs - Use for OAuth token format (572 lines)
  • session/ - Use for refresh token sessions (802 lines)
  • permissions/ - Map to OAuth scopes (703 lines)
  • transport/ - Adapt for Bearer token extraction
  • middleware/ - Adapt for OAuth validation

Net change: -3,150 lines of API key code, +3,000 lines of OAuth code = ~0 net lines

Phase 4: Migration Path

For backward compatibility, we could:

  1. Dual mode: Support both API keys and OAuth temporarily
  2. Auto-migration: Convert existing API keys to OAuth clients
  3. Deprecation: Mark API key methods as #[deprecated]
  4. Remove: Delete API key code in next major version

Or aggressive approach:

  1. Delete API key code immediately
  2. Only support OAuth 2.1 going forward
  3. Breaking change for v1.0.0

Implementation Checklist

  • Research Rust OAuth libraries (oxide-auth vs. oauth2 vs. custom)
  • Design OAuth server architecture
  • Implement PKCE (Proof Key for Code Exchange)
  • Implement authorization endpoint
  • Implement token endpoint
  • Implement dynamic client registration (RFC 7591)
  • Implement authorization server metadata endpoint (RFC 8414)
  • Implement resource parameter binding (RFC 8707)
  • Map RBAC permissions to OAuth scopes
  • Update middleware for Bearer token validation
  • Update transport extractors for OAuth
  • Add OAuth examples and documentation
  • Write integration tests against MCP spec
  • Migration guide for existing API key users
  • Delete API key system

Benefits

MCP Spec Compliant - Works with standard MCP clients
Industry Standard - OAuth 2.1 is well-understood and battle-tested
Better Security - PKCE, dynamic registration, proper token validation
Simpler - Remove 3,150 lines of custom API key code
Interoperable - Can use standard OAuth tools and libraries
Scalable - OAuth designed for distributed systems

Risks

⚠️ Breaking Change - Existing API key users must migrate
⚠️ Complexity - OAuth implementation is non-trivial
⚠️ Dependencies - May need external OAuth library
⚠️ Testing - Need comprehensive OAuth flow testing

Questions to Resolve

  1. Should we use an existing Rust OAuth library or implement from scratch?
  2. Do we support both API keys and OAuth during migration, or clean break?
  3. What's the migration timeline (immediate vs. gradual deprecation)?
  4. Should OAuth be optional feature or always-on for HTTP transports?
  5. Do we implement both OAuth server + client, or just server?

Related Issues

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions