-
-
Notifications
You must be signed in to change notification settings - Fork 919
fix: authorization resource for EXTERNAL_OAUTH21_PROVIDER=true #405
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
de461c7
fix the authorization resource for EXTERNAL_OAUTH21_PROVIDER=true
6bb10b2
ruff
taylorwilsdon 1c559dc
Apply suggestions from code review
ryohang 47959d2
feat(forms): Add batch_update_form tool for Google Forms API
ugoano d7c6e35
docs: Add batch_update_form to tool tiers and README documentation
ugoano a96ad43
add checks for maintainer access and PR template
taylorwilsdon 8bfbeca
cleanup
taylorwilsdon 0d8dc4c
merge
taylorwilsdon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,33 +3,54 @@ | |
|
|
||
| Extends FastMCP's GoogleProvider to support external OAuth flows where | ||
| access tokens (ya29.*) are issued by external systems and need validation. | ||
|
|
||
| This provider acts as a Resource Server only - it validates tokens issued by | ||
| Google's Authorization Server but does not issue tokens itself. | ||
| """ | ||
|
|
||
| import logging | ||
| import time | ||
| from typing import Optional | ||
|
|
||
| from starlette.routing import Route | ||
| from fastmcp.server.auth.providers.google import GoogleProvider | ||
| from fastmcp.server.auth import AccessToken | ||
| from google.oauth2.credentials import Credentials | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| # Google's OAuth 2.0 Authorization Server | ||
| GOOGLE_ISSUER_URL = "https://accounts.google.com" | ||
|
|
||
|
|
||
| class ExternalOAuthProvider(GoogleProvider): | ||
| """ | ||
| Extended GoogleProvider that supports validating external Google OAuth access tokens. | ||
|
|
||
| This provider handles ya29.* access tokens by calling Google's userinfo API, | ||
| while maintaining compatibility with standard JWT ID tokens. | ||
|
|
||
| Unlike the standard GoogleProvider, this acts as a Resource Server only: | ||
| - Does NOT create /authorize, /token, /register endpoints | ||
| - Only advertises Google's authorization server in metadata | ||
| - Only validates tokens, does not issue them | ||
| """ | ||
|
|
||
| def __init__(self, client_id: str, client_secret: str, **kwargs): | ||
| def __init__( | ||
| self, | ||
| client_id: str, | ||
| client_secret: str, | ||
| resource_server_url: Optional[str] = None, | ||
| **kwargs, | ||
| ): | ||
| """Initialize and store client credentials for token validation.""" | ||
| self._resource_server_url = resource_server_url | ||
| super().__init__(client_id=client_id, client_secret=client_secret, **kwargs) | ||
| # Store credentials as they're not exposed by parent class | ||
| self._client_id = client_id | ||
| self._client_secret = client_secret | ||
| # Store as string - Pydantic validates it when passed to models | ||
| self.resource_server_url = self._resource_server_url | ||
|
|
||
| async def verify_token(self, token: str) -> Optional[AccessToken]: | ||
| """ | ||
|
|
@@ -97,3 +118,40 @@ async def verify_token(self, token: str) -> Optional[AccessToken]: | |
|
|
||
| # For JWT tokens, use parent class implementation | ||
| return await super().verify_token(token) | ||
|
|
||
| def get_routes(self, **kwargs) -> list[Route]: | ||
| """ | ||
| Get OAuth routes for external provider mode. | ||
|
|
||
| Returns only protected resource metadata routes that point to Google | ||
| as the authorization server. Does not create authorization server routes | ||
| (/authorize, /token, etc.) since tokens are issued by Google directly. | ||
|
|
||
| Args: | ||
| **kwargs: Additional arguments passed by FastMCP (e.g., mcp_path) | ||
|
|
||
| Returns: | ||
| List of routes - only protected resource metadata | ||
| """ | ||
| from mcp.server.auth.routes import create_protected_resource_routes | ||
|
||
|
|
||
| if not self.resource_server_url: | ||
| logger.warning( | ||
| "ExternalOAuthProvider: resource_server_url not set, no routes created" | ||
| ) | ||
| return [] | ||
|
|
||
| # Create protected resource routes that point to Google as the authorization server | ||
| # Pass strings directly - Pydantic validates them during model construction | ||
| protected_routes = create_protected_resource_routes( | ||
| resource_url=self.resource_server_url, | ||
| authorization_servers=[GOOGLE_ISSUER_URL], | ||
| scopes_supported=self.required_scopes, | ||
| resource_name="Google Workspace MCP", | ||
| resource_documentation=None, | ||
| ) | ||
|
|
||
| logger.info( | ||
| f"ExternalOAuthProvider: Created protected resource routes pointing to {GOOGLE_ISSUER_URL}" | ||
| ) | ||
| return protected_routes | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment mentions Pydantic validation but the assignment is a simple string copy without any validation happening at this point. Consider removing the misleading comment or adding actual validation if needed.