AuthKit: auto-bind token audience to resource URL (RFC 8707) (#3905)

This commit is contained in:
Jeremiah Lowin 2026-04-13 17:11:17 -04:00 committed by GitHub
commit 82f310fe61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 265 additions and 114 deletions

View file

@ -0,0 +1,36 @@
# AuthKit Example
Protects a FastMCP server with WorkOS AuthKit. The server binds the JWT
`aud` claim to its own resource URL automatically — you just paste that same
URL into the WorkOS Dashboard as a resource indicator.
## WorkOS Dashboard setup
In the WorkOS Dashboard for your project, go to **Connect → Configuration** and:
1. Under **MCP Auth**, enable **Dynamic Client Registration** (or **Client ID
Metadata Document** if your MCP client supports it).
2. Under **MCP resource indicators**, add `http://127.0.0.1:8000/mcp` as a
valid resource indicator.
## Running
1. Set your AuthKit domain:
```bash
export AUTHKIT_DOMAIN="https://your-app.authkit.app"
```
2. Start the server. It logs the resource URL it's validating against —
that's the URL that must match your dashboard resource indicator:
```bash
python server.py
```
3. In another terminal, run the client. Your browser will open for AuthKit
authentication:
```bash
python client.py
```

View file

@ -1,9 +1,11 @@
"""AuthKit DCR server example for FastMCP.
"""AuthKit server example for FastMCP.
This example demonstrates how to protect a FastMCP server with AuthKit DCR.
Demonstrates an MCP server secured by WorkOS AuthKit. FastMCP binds the JWT
audience to this server's resource URL automatically; you configure the same
URL as an MCP resource indicator in the WorkOS Dashboard.
Required environment variables:
- FASTMCP_SERVER_AUTH_AUTHKITPROVIDER_AUTHKIT_DOMAIN: Your AuthKit domain (e.g., "https://your-app.authkit.app")
- AUTHKIT_DOMAIN: Your AuthKit domain (e.g., "https://your-app.authkit.app")
To run:
python server.py
@ -16,10 +18,10 @@ from fastmcp.server.auth.providers.workos import AuthKitProvider
auth = AuthKitProvider(
authkit_domain=os.getenv("AUTHKIT_DOMAIN") or "",
base_url="http://localhost:8000",
base_url="http://127.0.0.1:8000",
)
mcp = FastMCP("AuthKit DCR Example Server", auth=auth)
mcp = FastMCP("AuthKit Example Server", auth=auth)
@mcp.tool

View file

@ -1,25 +0,0 @@
# AuthKit DCR Example
Demonstrates FastMCP server protection with AuthKit Dynamic Client Registration.
## Setup
1. Set your AuthKit domain:
```bash
export AUTHKIT_DOMAIN="https://your-app.authkit.app"
```
2. Run the server:
```bash
python server.py
```
3. In another terminal, run the client:
```bash
python client.py
```
The client will open your browser for AuthKit authentication.

View file

@ -10,7 +10,7 @@ Demonstrates FastMCP server protection with AWS Cognito OAuth.
- Create an App Client in your User Pool
- Configure the App Client settings:
- Enable "Authorization code grant" flow
- Add Callback URL: `http://localhost:8000/auth/callback`
- Add Callback URL: `http://127.0.0.1:8000/auth/callback`
- Configure OAuth scopes (at minimum: `openid`)
- Note your User Pool ID, App Client ID, Client Secret, and Cognito Domain Prefix

View file

@ -10,7 +10,7 @@ import asyncio
from fastmcp.client import Client
SERVER_URL = "http://localhost:8000/mcp"
SERVER_URL = "http://127.0.0.1:8000/mcp"
async def main():

View file

@ -31,7 +31,7 @@ auth = AWSCognitoProvider(
or "eu-central-1",
client_id=os.getenv("FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_ID") or "",
client_secret=os.getenv("FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_SECRET") or "",
base_url="http://localhost:8000",
base_url="http://127.0.0.1:8000",
# redirect_path="/custom/callback"
)

View file

@ -10,7 +10,7 @@ This example demonstrates how to use the Azure OAuth provider with FastMCP serve
2. Click "New registration" and configure:
- Name: Your app name
- Supported account types: Choose based on your needs
- Redirect URI: `http://localhost:8000/auth/callback` (Web platform)
- Redirect URI: `http://127.0.0.1:8000/auth/callback` (Web platform)
3. After creation, go to "Certificates & secrets" → "New client secret"
4. Note these values from the Overview page:
- Application (client) ID

View file

@ -24,7 +24,7 @@ auth = AzureProvider(
client_secret=os.getenv("FASTMCP_SERVER_AUTH_AZURE_CLIENT_SECRET") or "",
tenant_id=os.getenv("FASTMCP_SERVER_AUTH_AZURE_TENANT_ID")
or "", # Required for single-tenant apps - get from Azure Portal
base_url="http://localhost:8000",
base_url="http://127.0.0.1:8000",
required_scopes=["read"],
# required_scopes is automatically loaded from FASTMCP_SERVER_AUTH_AZURE_REQUIRED_SCOPES
# At least one scope is required - use unprefixed scope names from your Azure App (e.g., ["read", "write"])

View file

@ -9,7 +9,7 @@ Demonstrates FastMCP server protection with Clerk OAuth.
- Create or select an application
- Go to Developers > OAuth Applications
- Create an OAuth application
- Add Authorized redirect URI: `http://localhost:8000/auth/callback`
- Add Authorized redirect URI: `http://127.0.0.1:8000/auth/callback`
- Copy the Client ID and Client Secret
- Note your instance domain (e.g., `saving-primate-16.clerk.accounts.dev`)

View file

@ -21,7 +21,7 @@ auth = ClerkProvider(
domain=os.getenv("FASTMCP_SERVER_AUTH_CLERK_DOMAIN") or "",
client_id=os.getenv("FASTMCP_SERVER_AUTH_CLERK_CLIENT_ID") or "",
client_secret=os.getenv("FASTMCP_SERVER_AUTH_CLERK_CLIENT_SECRET") or "",
base_url="http://localhost:8000",
base_url="http://127.0.0.1:8000",
# redirect_path="/auth/callback", # Default path - change if using a different callback URL
# Optional: specify required scopes (defaults to ["openid", "email", "profile"])
# required_scopes=["openid", "email", "profile", "public_metadata"],

View file

@ -8,7 +8,7 @@ Demonstrates FastMCP server protection with Discord OAuth.
- Go to https://discord.com/developers/applications
- Click "New Application" and give it a name
- Go to OAuth2 in the left sidebar
- Add a Redirect URL: `http://localhost:8000/auth/callback`
- Add a Redirect URL: `http://127.0.0.1:8000/auth/callback`
- Copy the Client ID and Client Secret
2. Set environment variables:

View file

@ -18,7 +18,7 @@ from fastmcp.server.auth.providers.discord import DiscordProvider
auth = DiscordProvider(
client_id=os.getenv("FASTMCP_SERVER_AUTH_DISCORD_CLIENT_ID") or "",
client_secret=os.getenv("FASTMCP_SERVER_AUTH_DISCORD_CLIENT_SECRET") or "",
base_url="http://localhost:8000",
base_url="http://127.0.0.1:8000",
# redirect_path="/auth/callback", # Default path - change if using a different callback URL
)

View file

@ -6,7 +6,7 @@ Demonstrates FastMCP server protection with GitHub OAuth.
1. Create a GitHub OAuth App:
- Go to GitHub Settings > Developer settings > OAuth Apps
- Set Authorization callback URL to: `http://localhost:8000/auth/callback`
- Set Authorization callback URL to: `http://127.0.0.1:8000/auth/callback`
- Copy the Client ID and Client Secret
2. Set environment variables:

View file

@ -10,7 +10,7 @@ import asyncio
from fastmcp.client import Client, OAuth
SERVER_URL = "http://localhost:8000/mcp"
SERVER_URL = "http://127.0.0.1:8000/mcp"
async def main():

View file

@ -18,7 +18,7 @@ from fastmcp.server.auth.providers.github import GitHubProvider
auth = GitHubProvider(
client_id=os.getenv("FASTMCP_SERVER_AUTH_GITHUB_CLIENT_ID") or "",
client_secret=os.getenv("FASTMCP_SERVER_AUTH_GITHUB_CLIENT_SECRET") or "",
base_url="http://localhost:8000",
base_url="http://127.0.0.1:8000",
# redirect_path="/auth/callback", # Default path - change if using a different callback URL
)

View file

@ -9,7 +9,7 @@ Demonstrates FastMCP server protection with Google OAuth.
- Create or select a project
- Go to APIs & Services > Credentials
- Create OAuth 2.0 Client ID (Web application)
- Add Authorized redirect URI: `http://localhost:8000/auth/callback`
- Add Authorized redirect URI: `http://127.0.0.1:8000/auth/callback`
- Copy the Client ID and Client Secret
2. Set environment variables:

View file

@ -18,7 +18,7 @@ from fastmcp.server.auth.providers.google import GoogleProvider
auth = GoogleProvider(
client_id=os.getenv("FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_ID") or "",
client_secret=os.getenv("FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_SECRET") or "",
base_url="http://localhost:8000",
base_url="http://127.0.0.1:8000",
# redirect_path="/auth/callback", # Default path - change if using a different callback URL
# Optional: specify required scopes
# required_scopes=["openid", "https://www.googleapis.com/auth/userinfo.email"],

View file

@ -6,7 +6,7 @@ Demonstrates FastMCP server protection with Keycloak OAuth.
## Setup
1. Configure a Keycloak realm with Dynamic Client Registration enabled and a trusted host policy for your server URL (e.g. `http://localhost:8000/*`).
1. Configure a Keycloak realm with Dynamic Client Registration enabled and a trusted host policy for your server URL (e.g. `http://127.0.0.1:8000/*`).
2. Set environment variables:

View file

@ -8,7 +8,7 @@ import asyncio
from fastmcp import Client
SERVER_URL = "http://localhost:8000/mcp"
SERVER_URL = "http://127.0.0.1:8000/mcp"
async def main():

View file

@ -16,8 +16,8 @@ from fastmcp.server.dependencies import get_access_token
auth = KeycloakAuthProvider(
realm_url=os.getenv("KEYCLOAK_REALM_URL") or "http://localhost:8080/realms/fastmcp",
base_url="http://localhost:8000",
# audience="http://localhost:8000", # Recommended for production
base_url="http://127.0.0.1:8000",
# audience="http://127.0.0.1:8000", # Recommended for production
)
mcp = FastMCP("Keycloak Example Server", auth=auth)

View file

@ -4,12 +4,12 @@ This example demonstrates mounting multiple OAuth-protected MCP servers in a sin
## URL Structure
- **GitHub MCP**: `http://localhost:8000/api/mcp/github/mcp`
- **Google MCP**: `http://localhost:8000/api/mcp/google/mcp`
- **GitHub MCP**: `http://127.0.0.1:8000/api/mcp/github/mcp`
- **Google MCP**: `http://127.0.0.1:8000/api/mcp/google/mcp`
Discovery endpoints (RFC 8414 path-aware):
- **GitHub**: `http://localhost:8000/.well-known/oauth-authorization-server/api/mcp/github`
- **Google**: `http://localhost:8000/.well-known/oauth-authorization-server/api/mcp/google`
- **GitHub**: `http://127.0.0.1:8000/.well-known/oauth-authorization-server/api/mcp/github`
- **Google**: `http://127.0.0.1:8000/.well-known/oauth-authorization-server/api/mcp/google`
## Setup
@ -23,8 +23,8 @@ export FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_SECRET="your-google-client-secret"
```
Configure redirect URIs in each provider's developer console (note the `/api/mcp/{provider}` prefix since the servers are mounted):
- GitHub: `http://localhost:8000/api/mcp/github/auth/callback/github`
- Google: `http://localhost:8000/api/mcp/google/auth/callback/google`
- GitHub: `http://127.0.0.1:8000/api/mcp/github/auth/callback/github`
- Google: `http://127.0.0.1:8000/api/mcp/google/auth/callback/google`
## Running

View file

@ -5,10 +5,10 @@ application, each with its own provider. It showcases RFC 8414 path-aware discov
where each server has its own authorization server metadata endpoint.
URL structure:
- GitHub MCP: http://localhost:8000/api/mcp/github/mcp
- Google MCP: http://localhost:8000/api/mcp/google/mcp
- GitHub discovery: http://localhost:8000/.well-known/oauth-authorization-server/api/mcp/github
- Google discovery: http://localhost:8000/.well-known/oauth-authorization-server/api/mcp/google
- GitHub MCP: http://127.0.0.1:8000/api/mcp/github/mcp
- Google MCP: http://127.0.0.1:8000/api/mcp/google/mcp
- GitHub discovery: http://127.0.0.1:8000/.well-known/oauth-authorization-server/api/mcp/github
- Google discovery: http://127.0.0.1:8000/.well-known/oauth-authorization-server/api/mcp/google
Required environment variables:
- FASTMCP_SERVER_AUTH_GITHUB_CLIENT_ID: Your GitHub OAuth app client ID
@ -31,7 +31,7 @@ from fastmcp.server.auth.providers.github import GitHubProvider
from fastmcp.server.auth.providers.google import GoogleProvider
# Configuration
ROOT_URL = "http://localhost:8000"
ROOT_URL = "http://127.0.0.1:8000"
API_PREFIX = "/api/mcp"
# --- GitHub OAuth Server ---

View file

@ -36,7 +36,7 @@ Create a `.env` file:
PROPELAUTH_AUTH_URL=https://auth.yourdomain.com
PROPELAUTH_INTROSPECTION_CLIENT_ID=your-client-id
PROPELAUTH_INTROSPECTION_CLIENT_SECRET=your-client-secret
BASE_URL=http://localhost:8000/
BASE_URL=http://127.0.0.1:8000/
# Optional: additional scopes tokens must include (comma-separated)
# PROPELAUTH_REQUIRED_SCOPES=read:user_data
```
@ -50,7 +50,7 @@ Start the server:
uv run python server.py
```
The server will start on `http://localhost:8000/mcp` with PropelAuth OAuth authentication enabled.
The server will start on `http://127.0.0.1:8000/mcp` with PropelAuth OAuth authentication enabled.
Test with client:

View file

@ -9,7 +9,7 @@ Required environment variables:
Optional:
- PROPELAUTH_REQUIRED_SCOPES: Comma-separated scopes tokens must include
- BASE_URL: Public URL where the FastMCP server is exposed (defaults to `http://localhost:8000/`)
- BASE_URL: Public URL where the FastMCP server is exposed (defaults to `http://127.0.0.1:8000/`)
To run:
python server.py
@ -29,7 +29,7 @@ auth = PropelAuthProvider(
auth_url=os.environ["PROPELAUTH_AUTH_URL"],
introspection_client_id=os.environ["PROPELAUTH_INTROSPECTION_CLIENT_ID"],
introspection_client_secret=os.environ["PROPELAUTH_INTROSPECTION_CLIENT_SECRET"],
base_url=os.getenv("BASE_URL", "http://localhost:8000/"),
base_url=os.getenv("BASE_URL", "http://127.0.0.1:8000/"),
)
mcp = FastMCP("PropelAuth OAuth Example Server", auth=auth)

View file

@ -24,7 +24,7 @@ Create a `.env` file:
# Required Scalekit credentials
SCALEKIT_ENVIRONMENT_URL=<YOUR_APP_ENVIRONMENT_URL>
SCALEKIT_RESOURCE_ID=<YOUR_APP_RESOURCE_ID> # res_926EXAMPLE5878
BASE_URL=http://localhost:8000/
BASE_URL=http://127.0.0.1:8000/
# Optional: additional scopes tokens must include (comma-separated)
# SCALEKIT_REQUIRED_SCOPES=read,write
```
@ -38,7 +38,7 @@ Start the server:
uv run python server.py
```
The server will start on `http://localhost:8000/mcp` with Scalekit OAuth authentication enabled.
The server will start on `http://127.0.0.1:8000/mcp` with Scalekit OAuth authentication enabled.
Test with client:

View file

@ -8,7 +8,7 @@ Required environment variables:
Optional:
- SCALEKIT_REQUIRED_SCOPES: Comma-separated scopes tokens must include
- BASE_URL: Public URL where the FastMCP server is exposed (defaults to `http://localhost:8000/`)
- BASE_URL: Public URL where the FastMCP server is exposed (defaults to `http://127.0.0.1:8000/`)
To run:
python server.py
@ -30,7 +30,7 @@ auth = ScalekitProvider(
environment_url=os.getenv("SCALEKIT_ENVIRONMENT_URL")
or "https://your-env.scalekit.com",
resource_id=os.getenv("SCALEKIT_RESOURCE_ID") or "",
base_url=os.getenv("BASE_URL", "http://localhost:8000/"),
base_url=os.getenv("BASE_URL", "http://127.0.0.1:8000/"),
required_scopes=required_scopes,
)

View file

@ -20,7 +20,7 @@ auth = WorkOSProvider(
client_id=os.getenv("WORKOS_CLIENT_ID") or "",
client_secret=os.getenv("WORKOS_CLIENT_SECRET") or "",
authkit_domain=os.getenv("WORKOS_AUTHKIT_DOMAIN") or "https://your-app.authkit.app",
base_url="http://localhost:8000",
base_url="http://127.0.0.1:8000",
# redirect_path="/auth/callback", # Default path - change if using a different callback URL
)