Authentication
Implement OAuth 2.0 and API key authentication in your GolfMCP servers.
GolfMCP provides two authentication mechanisms to secure your MCP servers:
- OAuth 2.0 - For user-based authentication with external identity providers
- API Key - For simple pass-through authentication to upstream APIs
API key authentication
Overview
Golf provides a simple API key pass-through authentication mechanism that allows MCP servers to extract API keys from request headers and forward them to upstream services. The actual authentication happens at the destination API level, not within the MCP server.
Configuration
Configure API key extraction in your project’s pre_build.py
:
How it works
- Middleware: Golf automatically adds middleware that extracts the API key from incoming request headers
- Context Storage: The extracted key is stored in a request-scoped context (only exists for the duration of the request)
- Tool Access: Tools retrieve the API key using
get_api_key()
- Pass-through: Tools forward the key to upstream APIs in whatever format they require
Using in tools
Tools access the API key with a simple import:
Complete example: GitHub API tool
Here’s a complete example of a GitHub tool using API key authentication:
pre_build.py:
tools/repos/list.py:
Common configuration patterns
X-API-Key Header (many APIs):
Authorization with Different Prefixes:
OAuth 2.0 authentication
GolfMCP provides a high-level abstraction for OAuth 2.0 integration, allowing you to configure authentication without manually implementing the MCP SDK’s OAuthAuthorizationServerProvider
interface.
Core concepts
-
ProviderConfig
(golf.auth.provider.ProviderConfig
): A Pydantic model used to define the settings for an external OAuth 2.0 identity provider (IdP). Key fields include:provider
: A string identifying the provider (e.g.,"github"
,"google"
, or"custom"
).client_id_env_var
: The name of the environment variable holding the OAuth Client ID.client_secret_env_var
: The name of the environment variable holding the OAuth Client Secret.jwt_secret_env_var
: The name of the environment variable holding the secret key for signing JWTs issued by your GolfMCP server.authorize_url
: The IdP’s authorization endpoint URL.token_url
: The IdP’s token endpoint URL.userinfo_url
(Optional): The IdP’s userinfo endpoint URL.scopes
: A list of scopes to request from the IdP (e.g.,["read:user", "openid"]
).issuer_url
: The publicly accessible base URL of your GolfMCP server. This is crucial as it’s used as theiss
(issuer) claim in JWTs your server generates and for constructing callback URLs.callback_path
: The path on your GolfMCP server where the IdP should redirect after authentication (e.g.,"/auth/callback"
).token_expiration
: The lifetime (in seconds) for JWTs issued by your GolfMCP server.
-
configure_auth
(golf.auth.configure_auth
): A function, typically called inpre_build.py
, to register the authentication provider configuration with GolfMCP.This function stores the
provider_config
andrequired_scopes
globally, which the build process then uses. -
GolfOAuthProvider
(golf.auth.oauth.GolfOAuthProvider
): The heart of Golf’s auth abstraction. This class implements the MCP SDK’sOAuthAuthorizationServerProvider
interface. It’s initialized with theProviderConfig
you define.- OAuth Flow Management: It handles the Authorization Code Grant flow:
- Redirecting users to the IdP’s
authorize_url
. - Exchanging the authorization code (received at
callback_path
) for tokens at the IdP’stoken_url
. - Fetching user information (if
userinfo_url
is provided).
- Redirecting users to the IdP’s
- JWT Issuance: After successful authentication with the IdP,
GolfOAuthProvider
mints its own JWT. This JWT represents the user’s session with your GolfMCP server.- The JWT is signed using the
jwt_secret
(loaded fromjwt_secret_env_var
). - It includes standard claims like
iss
(your server’sissuer_url
),sub
(subject, often client ID),exp
(expiration),iat
(issued at), andscp
(scopes).
- The JWT is signed using the
- Token Storage (
TokenStorage
ingolf.auth.oauth
):- A simple in-memory dictionary-based storage for:
- Authorization codes (temporary).
- Refresh tokens.
- Access tokens (primarily for JWT verification state, though JWTs are self-contained).
- Mappings between your server’s access tokens and the IdP’s access tokens (e.g., to store the GitHub token).
- Note: This in-memory storage is suitable for development and simple use cases. For production, a persistent and more robust token storage solution (e.g., Redis, database) would be necessary. (This is part of the roadmap).
- A simple in-memory dictionary-based storage for:
- OAuth Flow Management: It handles the Authorization Code Grant flow:
-
Callback Handling (
create_callback_handler
ingolf.auth.oauth
): This function takes aGolfOAuthProvider
instance and returns anasync
HTTP request handler. The build process uses this to generate the route for yourcallback_path
(e.g.,/auth/callback
) in thedist/server.py
. This handler processes the redirect from the IdP.
How secrets are handled
A key design principle is that sensitive secrets (Client ID, Client Secret, JWT Secret) are not hardcoded or stored directly in your project files or the built distributable.
- You define environment variable names in
ProviderConfig
(e.g.,client_id_env_var="MY_APP_CLIENT_ID"
). - During the
golf build
process, theCodeGenerator
(specifically_generate_server
and the auth-related code inbuilder_auth.py
) writes Python code intodist/server.py
. - This generated code in
dist/server.py
includes lines likeruntime_client_id = os.environ.get("MY_APP_CLIENT_ID")
. - When you run
golf run
(or executepython dist/server.py
), the server, at startup, reads the actual secret values from the environment variables of the system it’s running on. - These runtime-loaded secrets are then used to initialize the
GolfOAuthProvider
instance.
This ensures that your dist/
directory can be safely distributed or committed (if needed, though typically dist/
is in .gitignore
) without exposing secrets. Secrets must be present in the environment where the server runs.
Accessing provider tokens (e.g., GitHub token)
If your tools need to make API calls to the external provider on behalf of the user (e.g., call the GitHub API), you can retrieve the IdP’s access token that GolfMCP stored during the OAuth flow.
The get_provider_token()
function (from golf.auth.helpers
) looks up the mapping between the current GolfMCP session’s access token and the stored external provider’s access token.