Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/development/upgrade-guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,31 @@ def my_prompt() -> Message:

See [Prompts documentation](/servers/prompts#return-values) for full details.

### Auth Provider Automatic Environment Variable Loading Removed

Auth providers no longer automatically read configuration from environment variables. You can still use environment variables, but you must read them yourself:

<CodeGroup>
```python Before
# Relied on FASTMCP_SERVER_AUTH_GITHUB_CLIENT_ID, etc.
auth = GitHubProvider()
```

```python After
import os

auth = GitHubProvider(
client_id=os.environ["GITHUB_CLIENT_ID"],
client_secret=os.environ["GITHUB_CLIENT_SECRET"],
base_url=os.environ["GITHUB_BASE_URL"],
)
```
</CodeGroup>

This applies to all auth providers: `GitHubProvider`, `GoogleProvider`, `AzureProvider`, `Auth0Provider`, `AWSProvider`, `WorkOSProvider`, `DescopeProvider`, `DiscordProvider`, `ScalekitProvider`, `SupabaseProvider`, `OCIProvider`, `JWTVerifier`, and `IntrospectionVerifier`.

The `FastMCPSettings` class has also been simplified - it no longer includes auth-related settings that were previously loaded from environment variables.

## v2.14.0

### OpenAPI Parser Promotion
Expand Down
73 changes: 73 additions & 0 deletions docs/development/v3-notes/auth-provider-env-vars.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: Auth Provider Environment Variables
---

## Decision: Remove automatic environment variable loading from auth providers

You can still use environment variables for configuration - you just read them yourself with `os.environ` instead of relying on FastMCP's automatic loading.

**Status:** Implemented in v3.0.0

### Background

Auth providers in v2.x used `pydantic-settings` to automatically load configuration from environment variables with a `FASTMCP_SERVER_AUTH_<PROVIDER>_` prefix. For example, `GitHubProvider` would read from:

- `FASTMCP_SERVER_AUTH_GITHUB_CLIENT_ID`
- `FASTMCP_SERVER_AUTH_GITHUB_CLIENT_SECRET`
- `FASTMCP_SERVER_AUTH_GITHUB_BASE_URL`
- etc.

This was implemented via a `*ProviderSettings(BaseSettings)` class in each provider, combined with a `NotSet` sentinel pattern to distinguish between "not provided" and `None`.

### Why remove it

1. **Maintenance burden**: Every new provider needed to implement the settings class, validators, and the `NotSet` merging logic. This was ~50-100 lines of boilerplate per provider.

2. **Documentation complexity**: Each provider needed documentation explaining both the parameter and the corresponding environment variable. This doubled the surface area to document and maintain.

3. **Contributor friction**: New contributors adding providers had to understand and replicate this pattern, which was a source of inconsistency and bugs.

4. **Marginal user value**: Python developers are comfortable with `os.environ["VAR"]` or `os.environ.get("VAR", default)`. The automatic loading saved a single line of code per parameter while adding significant complexity.

5. **Implicit behavior**: Magic environment variable loading makes it harder to understand where values come from. Explicit `os.environ` calls are more traceable.

### Migration path

The migration is trivial - users add explicit environment variable reads:

```python
# Before (v2.x)
auth = GitHubProvider() # Relied on env vars

# After (v3.0)
import os

auth = GitHubProvider(
client_id=os.environ["GITHUB_CLIENT_ID"],
client_secret=os.environ["GITHUB_CLIENT_SECRET"],
base_url=os.environ["MY_BASE_URL"],
)
```

Users can also use `os.environ.get()` with defaults, or any other configuration library they prefer (dotenv, dynaconf, etc.).

### Backwards compatibility

We chose not to provide backwards compatibility because:

1. This is a major version bump (v3.0), which is the appropriate time for breaking changes
2. The migration is straightforward (add `os.environ` calls)
3. Maintaining compatibility would require keeping all the boilerplate we're trying to remove
4. The pattern was likely not heavily used - most production deployments pass secrets explicitly rather than relying on magic prefixes

### What was removed

- `*ProviderSettings(BaseSettings)` classes from all auth providers
- `NotSet` sentinel usage in provider constructors
- `pydantic-settings` dependency for auth providers
- Environment variable documentation from provider docs
- Related test cases for env var loading

### Result

Provider constructors are now simple and explicit. Required parameters are actually required (Python raises `TypeError` if missing), and optional parameters have clear defaults. The code is more readable and easier to maintain.
81 changes: 0 additions & 81 deletions docs/integrations/auth0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -194,84 +194,3 @@ For complete details on these parameters, see the [OAuth Proxy documentation](/s
<Info>
The client caches tokens locally, so you won't need to re-authenticate for subsequent runs unless the token expires or you explicitly clear the cache.
</Info>

## Environment Variables

For production deployments, use environment variables instead of hardcoding credentials.

### Provider Selection

Setting this environment variable allows the Auth0 provider to be used automatically without explicitly instantiating it in code.

<Card>
<ParamField path="FASTMCP_SERVER_AUTH" default="Not set">
Set to `fastmcp.server.auth.providers.auth0.Auth0Provider` to use Auth0 authentication.
</ParamField>
</Card>

### Auth0-Specific Configuration

These environment variables provide default values for the Auth0 provider, whether it's instantiated manually or configured via `FASTMCP_SERVER_AUTH`.

<Card>
<ParamField path="FASTMCP_SERVER_AUTH_AUTH0_CONFIG_URL" required>
Your Auth0 Application Configuration URL (e.g., `https://.../.well-known/openid-configuration`)
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AUTH0_CLIENT_ID" required>
Your Auth0 Application Client ID (e.g., `tv2ObNgaZAWWhhycr7Bz1LU2mxlnsmsB`)
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AUTH0_CLIENT_SECRET" required>
Your Auth0 Application Client Secret (e.g., `vPYqbjemq...`)
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AUTH0_AUDIENCE" required>
Your Auth0 API Audience
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AUTH0_BASE_URL" required>
Public URL where OAuth endpoints will be accessible (includes any mount path)
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AUTH0_ISSUER_URL" default="Uses BASE_URL">
Issuer URL for OAuth metadata (defaults to `BASE_URL`). Set to root-level URL when mounting under a path prefix to avoid 404 logs. See [HTTP Deployment guide](/deployment/http#mounting-authenticated-servers) for details.
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AUTH0_REDIRECT_PATH" default="/auth/callback">
Redirect path configured in your Auth0 Application
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AUTH0_REQUIRED_SCOPES" default='["openid"]'>
Comma-, space-, or JSON-separated list of required AUth0 scopes (e.g., `openid email` or `["openid","email"]`)
</ParamField>
</Card>

Example `.env` file:
```bash
# Use the Auth0 provider
FASTMCP_SERVER_AUTH=fastmcp.server.auth.providers.auth0.Auth0Provider

# Auth0 configuration and credentials
FASTMCP_SERVER_AUTH_AUTH0_CONFIG_URL=https://.../.well-known/openid-configuration
FASTMCP_SERVER_AUTH_AUTH0_CLIENT_ID=tv2ObNgaZAWWhhycr7Bz1LU2mxlnsmsB
FASTMCP_SERVER_AUTH_AUTH0_CLIENT_SECRET=vPYqbjemq...
FASTMCP_SERVER_AUTH_AUTH0_AUDIENCE=https://...
FASTMCP_SERVER_AUTH_AUTH0_BASE_URL=https://your-server.com
FASTMCP_SERVER_AUTH_AUTH0_REQUIRED_SCOPES=openid,email
```

With environment variables set, your server code simplifies to:

```python server.py
from fastmcp import FastMCP

# Authentication is automatically configured from environment
mcp = FastMCP(name="Auth0 Secured App")

@mcp.tool
async def search_logs() -> list[str]:
"""Search the service logs."""
# Your tool implementation here
pass
```
58 changes: 11 additions & 47 deletions docs/integrations/authkit.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,56 +78,20 @@ if __name__ == "__main__":
```


## Environment Variables
## Production Configuration

<VersionBadge version="2.12.1" />

For production deployments, use environment variables instead of hardcoding credentials.

### Provider Selection

Setting this environment variable allows the AuthKit provider to be used automatically without explicitly instantiating it in code.

<Card>
<ParamField path="FASTMCP_SERVER_AUTH" default="Not set">
Set to `fastmcp.server.auth.providers.workos.AuthKitProvider` to use AuthKit authentication.
</ParamField>
</Card>

### AuthKit-Specific Configuration

These environment variables provide default values for the AuthKit provider, whether it's instantiated manually or configured via `FASTMCP_SERVER_AUTH`.

<Card>
<ParamField path="FASTMCP_SERVER_AUTH_AUTHKITPROVIDER_AUTHKIT_DOMAIN" required>
Your AuthKit domain (e.g., `https://your-project-12345.authkit.app`)
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AUTHKITPROVIDER_BASE_URL" required>
Public URL of your FastMCP server (e.g., `https://your-server.com` or `http://localhost:8000` for development)
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AUTHKITPROVIDER_REQUIRED_SCOPES" default="[]">
Comma-, space-, or JSON-separated list of required OAuth scopes (e.g., `openid profile email` or `["openid", "profile", "email"]`)
</ParamField>
</Card>

Example `.env` file:
```bash
# Use the AuthKit provider
FASTMCP_SERVER_AUTH=fastmcp.server.auth.providers.workos.AuthKitProvider

# AuthKit configuration
FASTMCP_SERVER_AUTH_AUTHKITPROVIDER_AUTHKIT_DOMAIN=https://your-project-12345.authkit.app
FASTMCP_SERVER_AUTH_AUTHKITPROVIDER_BASE_URL=https://your-server.com
FASTMCP_SERVER_AUTH_AUTHKITPROVIDER_REQUIRED_SCOPES=openid,profile,email
```

With environment variables set, your server code simplifies to:
For production deployments, load sensitive configuration from environment variables:

```python server.py
import os
from fastmcp import FastMCP
from fastmcp.server.auth.providers.workos import AuthKitProvider

# Load configuration from environment variables
auth = AuthKitProvider(
authkit_domain=os.environ.get("AUTHKIT_DOMAIN"),
base_url=os.environ.get("BASE_URL", "https://your-server.com")
)

# Authentication is automatically configured from environment
mcp = FastMCP(name="AuthKit Secured App")
mcp = FastMCP(name="AuthKit Secured App", auth=auth)
```
86 changes: 0 additions & 86 deletions docs/integrations/aws-cognito.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -238,92 +238,6 @@ Parameters (`jwt_signing_key` and `client_storage`) work together to ensure toke
For complete details on these parameters, see the [OAuth Proxy documentation](/servers/auth/oauth-proxy#configuration-parameters).
</Note>

## Environment Variables

For production deployments, use environment variables instead of hardcoding credentials.

### Provider Selection

Setting this environment variable allows the AWS Cognito provider to be used automatically without explicitly instantiating it in code.

<Card>
<ParamField path="FASTMCP_SERVER_AUTH" default="Not set">
Set to `fastmcp.server.auth.providers.aws.AWSCognitoProvider` to use AWS Cognito authentication.
</ParamField>
</Card>

### AWS Cognito-Specific Configuration

These environment variables provide default values for the AWS Cognito provider, whether it's instantiated manually or configured via `FASTMCP_SERVER_AUTH`.

<Card>
<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_USER_POOL_ID" required>
Your AWS Cognito user pool ID (e.g., `eu-central-1_XXXXXXXXX`)
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_AWS_REGION" default="eu-central-1">
AWS region where your AWS Cognito user pool is located
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_ID" required>
Your AWS Cognito app client ID
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_SECRET" required>
Your AWS Cognito app client secret
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_BASE_URL" default="http://localhost:8000">
Public URL where OAuth endpoints will be accessible (includes any mount path)
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_ISSUER_URL" default="Uses BASE_URL">
Issuer URL for OAuth metadata (defaults to `BASE_URL`). Set to root-level URL when mounting under a path prefix to avoid 404 logs. See [HTTP Deployment guide](/deployment/http#mounting-authenticated-servers) for details.
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_REDIRECT_PATH" default="/auth/callback">
One of the redirect paths configured in your AWS Cognito app client
</ParamField>

<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_REQUIRED_SCOPES" default='["openid"]'>
Comma-, space-, or JSON-separated list of required OAuth scopes (e.g., `openid email` or `["openid","email","profile"]`)
</ParamField>
</Card>

Example `.env` file:
```bash
# Use the AWS Cognito provider
FASTMCP_SERVER_AUTH=fastmcp.server.auth.providers.aws.AWSCognitoProvider

# AWS Cognito credentials
FASTMCP_SERVER_AUTH_AWS_COGNITO_USER_POOL_ID=eu-central-1_XXXXXXXXX
FASTMCP_SERVER_AUTH_AWS_COGNITO_AWS_REGION=eu-central-1
FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_ID=your-app-client-id
FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_SECRET=your-app-client-secret
FASTMCP_SERVER_AUTH_AWS_COGNITO_BASE_URL=https://your-server.com
FASTMCP_SERVER_AUTH_AWS_COGNITO_REQUIRED_SCOPES=openid,email,profile
```

With environment variables set, your server code simplifies to:

```python server.py
from fastmcp import FastMCP
from fastmcp.server.dependencies import get_access_token

# Authentication is automatically configured from environment
mcp = FastMCP(name="AWS Cognito Secured App")

@mcp.tool
async def get_access_token_claims() -> dict:
"""Get the authenticated user's access token claims."""
token = get_access_token()
return {
"sub": token.claims.get("sub"),
"username": token.claims.get("username"),
"cognito:groups": token.claims.get("cognito:groups", []),
}
```

## Features

### JWT Token Validation
Expand Down
Loading