feat: add external OAuth 2.1 provider mode for bearer token authentication
Add support for external OAuth 2.1 provider mode where authentication is handled by external systems that issue Google OAuth access tokens. **Changes:** 1. **New Environment Variable: `EXTERNAL_OAUTH21_PROVIDER`** - Enables external OAuth mode when set to `true` - Requires `MCP_ENABLE_OAUTH21=true` - Disables protocol-level auth (MCP handshake/tools list work without auth) - Requires bearer tokens in Authorization headers for tool calls 2. **New File: `auth/external_oauth_provider.py`** - Custom provider extending FastMCP's GoogleProvider - Handles ya29.* Google OAuth access tokens - Validates tokens via google-auth library + userinfo API - Returns properly formatted AccessToken objects 3. **Modified: `auth/oauth_config.py`** - Add `external_oauth21_provider` config option - Validation that external mode requires OAuth 2.1 - Helper methods for checking external provider mode 4. **Modified: `core/server.py`** - Use ExternalOAuthProvider when external mode enabled - Use standard GoogleProvider otherwise - Set server.auth = None for external mode (no protocol auth) 5. **Modified: `README.md`** - New "External OAuth 2.1 Provider Mode" section - Usage examples and configuration - Added to environment variables table **How It Works:** - MCP handshake and tools/list do NOT require authentication - Tool calls require `Authorization: Bearer ya29.xxx` headers - Tokens validated by calling Google's userinfo API - Multi-user support via per-request authentication - Stateless-compatible for containerized deployments **Use Cases:** - Integrating with existing authentication systems - Custom OAuth flows managed by your application - API gateways handling authentication upstream - Multi-tenant SaaS with centralized auth - Mobile/web apps with their own OAuth implementation **Example Configuration:** ```bash export MCP_ENABLE_OAUTH21=true export EXTERNAL_OAUTH21_PROVIDER=true export GOOGLE_OAUTH_CLIENT_ID=your_client_id export GOOGLE_OAUTH_CLIENT_SECRET=your_client_secret export WORKSPACE_MCP_STATELESS_MODE=true # Optional ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -95,16 +95,38 @@ def configure_server_for_http():
|
||||
|
||||
try:
|
||||
required_scopes: List[str] = sorted(get_current_scopes())
|
||||
provider = GoogleProvider(
|
||||
client_id=config.client_id,
|
||||
client_secret=config.client_secret,
|
||||
base_url=config.get_oauth_base_url(),
|
||||
redirect_path=config.redirect_path,
|
||||
required_scopes=required_scopes,
|
||||
)
|
||||
server.auth = provider
|
||||
|
||||
# Check if external OAuth provider is configured
|
||||
if config.is_external_oauth21_provider():
|
||||
# External OAuth mode: use custom provider that handles ya29.* access tokens
|
||||
from auth.external_oauth_provider import ExternalOAuthProvider
|
||||
|
||||
provider = ExternalOAuthProvider(
|
||||
client_id=config.client_id,
|
||||
client_secret=config.client_secret,
|
||||
base_url=config.get_oauth_base_url(),
|
||||
redirect_path=config.redirect_path,
|
||||
required_scopes=required_scopes,
|
||||
)
|
||||
# Disable protocol-level auth, expect bearer tokens in tool calls
|
||||
server.auth = None
|
||||
logger.info("OAuth 2.1 enabled with EXTERNAL provider mode - protocol-level auth disabled")
|
||||
logger.info("Expecting Authorization bearer tokens in tool call headers")
|
||||
else:
|
||||
# Standard OAuth 2.1 mode: use FastMCP's GoogleProvider
|
||||
provider = GoogleProvider(
|
||||
client_id=config.client_id,
|
||||
client_secret=config.client_secret,
|
||||
base_url=config.get_oauth_base_url(),
|
||||
redirect_path=config.redirect_path,
|
||||
required_scopes=required_scopes,
|
||||
)
|
||||
# Enable protocol-level auth
|
||||
server.auth = provider
|
||||
logger.info("OAuth 2.1 enabled using FastMCP GoogleProvider with protocol-level auth")
|
||||
|
||||
# Always set auth provider for token validation in middleware
|
||||
set_auth_provider(provider)
|
||||
logger.info("OAuth 2.1 enabled using FastMCP GoogleProvider")
|
||||
_auth_provider = provider
|
||||
except Exception as exc:
|
||||
logger.error("Failed to initialize FastMCP GoogleProvider: %s", exc, exc_info=True)
|
||||
|
||||
Reference in New Issue
Block a user