Skip to content

Documentation Request: How to combine GoogleProvider OAuth with API key authentication #2499

@nick-youngblut

Description

@nick-youngblut

Description

Description

Use Case

I'm building an MCP server deployed on Google Cloud Run that needs to support two authentication methods:

  1. Google OAuth (via GoogleProvider) - for interactive clients like Claude Desktop
  2. Static API key - for programmatic/non-interactive access (CI/CD, scripts, service-to-service calls)

This is a common pattern for production APIs where you want both user-facing OAuth and machine-to-machine API key authentication.

What I Tried

I created a DualAuthProvider that extends GoogleProvider and overrides verify_token() to check for an API key first, then delegate to the parent:

from fastmcp.server.auth.providers.google import GoogleProvider
from mcp.server.auth.provider import AccessToken

class DualAuthProvider(GoogleProvider):
    def __init__(self, api_key: str, client_id: str, client_secret: str, base_url: str, **kwargs):
        self.api_key = api_key
        super().__init__(
            client_id=client_id,
            client_secret=client_secret,
            base_url=base_url,
            **kwargs,
        )

    async def verify_token(self, token: str) -> Optional[AccessToken]:
        # Check API key first
        if token == self.api_key:
            return AccessToken(
                token=token,
                client_id="api-key-client",
                scopes=["openid", "email", "profile"],
                expires_at=None,
            )
        
        # Delegate to GoogleProvider for OAuth tokens
        return await super().verify_token(token)

What Went Wrong

The OAuth flow completes successfully (token is issued via /token endpoint), but when the client uses the token, it's rejected with invalid_token:

POST /token HTTP/1.1" 200 OK          # Token issued successfully
POST /mcp HTTP/1.1" 401 Unauthorized  # Token immediately rejected
INFO Auth error returned: invalid_token

It appears that GoogleProvider.verify_token() expects Google-issued tokens (validated against Google's token endpoint), not the MCP server's self-issued OAuth tokens. By extending GoogleProvider and relying on super().verify_token(), I'm breaking the MCP token verification.

Request

Could you provide documentation or examples showing the recommended approach for combining GoogleProvider OAuth with API key authentication? Specifically:

  1. Is inheritance from GoogleProvider supported for adding custom token verification logic?
  2. Should composition be used instead (wrapping GoogleProvider rather than extending it)?
  3. Is middleware the right approach for API key auth while keeping GoogleProvider intact?
  4. Are there plans for a built-in DualAuthProvider or similar that supports this pattern?

Additional Context

This pattern would be valuable for many production deployments where:

  • Human users authenticate via OAuth (Claude Desktop, web clients)
  • Automated systems authenticate via API keys (CI/CD, monitoring, internal services)

The current documentation covers each auth method individually but doesn't address combining them.

Example Code

from fastmcp.server.auth.providers.google import GoogleProvider
from mcp.server.auth.provider import AccessToken

class DualAuthProvider(GoogleProvider):
    def __init__(self, api_key: str, client_id: str, client_secret: str, base_url: str, **kwargs):
        self.api_key = api_key
        super().__init__(
            client_id=client_id,
            client_secret=client_secret,
            base_url=base_url,
            **kwargs,
        )

    async def verify_token(self, token: str) -> Optional[AccessToken]:
        # Check API key first
        if token == self.api_key:
            return AccessToken(
                token=token,
                client_id="api-key-client",
                scopes=["openid", "email", "profile"],
                expires_at=None,
            )
        
        # Delegate to GoogleProvider for OAuth tokens
        return await super().verify_token(token)

Version Information

FastMCP version:                                                                2.13.0rc3.dev9+811e5166
MCP version:                                                                                     1.18.0
Python version:                                                                                 3.12.11
Platform:                                                                    macOS-26.1-arm64-arm-64bit
FastMCP root path: /Users/nickyoungblut/dev/python/arc-benchling-mcp/.venv/lib/python3.12/site-packages

Metadata

Metadata

Assignees

No one assigned

    Labels

    authRelated to authentication (Bearer, JWT, OAuth, WorkOS) for client or server.documentationUpdates to docs, examples, or guides. Primary change is documentation-related.duplicateDuplicates an existing open issue. Reference the original issue when applying.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions