Skip to content

Commit 82f310f

Browse files
authored
AuthKit: auto-bind token audience to resource URL (RFC 8707) (#3905)
1 parent c2dafc1 commit 82f310f

33 files changed

Lines changed: 265 additions & 114 deletions

File tree

docs/integrations/authkit.mdx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,32 @@ import { VersionBadge } from "/snippets/version-badge.mdx"
99

1010
<VersionBadge version="2.11.0" />
1111

12-
This guide shows you how to secure your FastMCP server using WorkOS's **AuthKit**, a complete authentication and user management solution. This integration uses the [**Remote OAuth**](/servers/auth/remote-oauth) pattern, where AuthKit handles user login and your FastMCP server validates the tokens.
13-
14-
<Warning>
15-
AuthKit does not currently support [RFC 8707](https://www.rfc-editor.org/rfc/rfc8707.html) resource indicators, so FastMCP cannot validate that tokens were issued for the specific resource server. If you need resource-specific audience validation, consider using [WorkOSProvider](/integrations/workos) (OAuth proxy pattern) instead.
16-
</Warning>
12+
This guide shows you how to secure your FastMCP server using WorkOS's **AuthKit**, a complete authentication and user management solution. This integration uses the [**Remote OAuth**](/servers/auth/remote-oauth) pattern with [RFC 8707](https://www.rfc-editor.org/rfc/rfc8707.html) resource indicators: AuthKit issues tokens whose `aud` claim is bound to your server's resource URL, and FastMCP validates that claim automatically.
1713

1814
## Configuration
15+
1916
### Prerequisites
2017

2118
Before you begin, you will need:
2219
1. A **[WorkOS Account](https://workos.com/)** and a new **Project**.
2320
2. An **[AuthKit](https://www.authkit.com/)** instance configured within your WorkOS project.
24-
3. Your FastMCP server's URL (can be localhost for development, e.g., `http://localhost:8000`).
21+
3. Your FastMCP server's URL (can be localhost for development, e.g., `http://127.0.0.1:8000`).
2522

26-
### Step 1: AuthKit Configuration
23+
### Step 1: WorkOS Dashboard
2724

28-
In your WorkOS Dashboard, enable AuthKit and configure the following settings:
25+
In the WorkOS Dashboard, go to **Connect → Configuration** and configure:
2926

3027
<Steps>
31-
<Step title="Enable Dynamic Client Registration">
32-
Go to **Applications → Configuration** and enable **Dynamic Client Registration**. This allows MCP clients register with your application automatically.
28+
<Step title="MCP Auth">
29+
Enable **Dynamic Client Registration** (DCR) so MCP clients can register themselves. Alternatively, enable **Client ID Metadata Document** (CIMD) if your clients support it.
30+
</Step>
3331

34-
![Enable Dynamic Client Registration](./images/authkit/enable_dcr.png)
32+
<Step title="MCP resource indicators">
33+
Add your FastMCP server's resource URL (e.g., `http://127.0.0.1:8000/mcp`) as a valid resource indicator.
34+
35+
This must exactly match what FastMCP advertises in its protected resource metadata. Start your server first and it will log the correct URL on startup — copy that value.
36+
37+
Without this step, AuthKit falls back to a default environment-scoped audience and audience validation will fail with a 401.
3538
</Step>
3639

3740
<Step title="Note Your AuthKit Domain">
@@ -47,16 +50,18 @@ Create your FastMCP server file and use the `AuthKitProvider` to handle all the
4750
from fastmcp import FastMCP
4851
from fastmcp.server.auth.providers.workos import AuthKitProvider
4952

50-
# The AuthKitProvider automatically discovers WorkOS endpoints
51-
# and configures JWT token validation
53+
# AuthKitProvider automatically discovers WorkOS endpoints, configures JWT
54+
# validation, and binds the token audience to this server's resource URL.
5255
auth_provider = AuthKitProvider(
5356
authkit_domain="https://your-project-12345.authkit.app",
54-
base_url="http://localhost:8000" # Use your actual server URL
57+
base_url="http://127.0.0.1:8000", # Use your actual server URL
5558
)
5659

5760
mcp = FastMCP(name="AuthKit Secured App", auth=auth_provider)
5861
```
5962

63+
When the server starts, it logs the resource URL it is validating against. Paste that URL into your Dashboard's **MCP resource indicators** list.
64+
6065
## Testing
6166

6267
To test your server, you can use the `fastmcp` CLI to run it locally. Assuming you've saved the above code to `server.py` (after replacing the `authkit_domain` and `base_url` with your actual values!), you can run the following command:
@@ -75,7 +80,7 @@ import asyncio
7580
auth = OAuth(additional_client_metadata={"token_endpoint_auth_method": "none"})
7681

7782
async def main():
78-
async with Client("http://localhost:8000/mcp", auth=auth) as client:
83+
async with Client("http://127.0.0.1:8000/mcp", auth=auth) as client:
7984
assert await client.ping()
8085

8186
if __name__ == "__main__":
@@ -94,7 +99,7 @@ from fastmcp.server.auth.providers.workos import AuthKitProvider
9499
# Load configuration from environment variables
95100
auth = AuthKitProvider(
96101
authkit_domain=os.environ.get("AUTHKIT_DOMAIN"),
97-
base_url=os.environ.get("BASE_URL", "https://your-server.com")
102+
base_url=os.environ.get("BASE_URL", "https://your-server.com"),
98103
)
99104

100105
mcp = FastMCP(name="AuthKit Secured App", auth=auth)

examples/auth/authkit/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# AuthKit Example
2+
3+
Protects a FastMCP server with WorkOS AuthKit. The server binds the JWT
4+
`aud` claim to its own resource URL automatically — you just paste that same
5+
URL into the WorkOS Dashboard as a resource indicator.
6+
7+
## WorkOS Dashboard setup
8+
9+
In the WorkOS Dashboard for your project, go to **Connect → Configuration** and:
10+
11+
1. Under **MCP Auth**, enable **Dynamic Client Registration** (or **Client ID
12+
Metadata Document** if your MCP client supports it).
13+
2. Under **MCP resource indicators**, add `http://127.0.0.1:8000/mcp` as a
14+
valid resource indicator.
15+
16+
## Running
17+
18+
1. Set your AuthKit domain:
19+
20+
```bash
21+
export AUTHKIT_DOMAIN="https://your-app.authkit.app"
22+
```
23+
24+
2. Start the server. It logs the resource URL it's validating against —
25+
that's the URL that must match your dashboard resource indicator:
26+
27+
```bash
28+
python server.py
29+
```
30+
31+
3. In another terminal, run the client. Your browser will open for AuthKit
32+
authentication:
33+
34+
```bash
35+
python client.py
36+
```
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
"""AuthKit DCR server example for FastMCP.
1+
"""AuthKit server example for FastMCP.
22
3-
This example demonstrates how to protect a FastMCP server with AuthKit DCR.
3+
Demonstrates an MCP server secured by WorkOS AuthKit. FastMCP binds the JWT
4+
audience to this server's resource URL automatically; you configure the same
5+
URL as an MCP resource indicator in the WorkOS Dashboard.
46
57
Required environment variables:
6-
- FASTMCP_SERVER_AUTH_AUTHKITPROVIDER_AUTHKIT_DOMAIN: Your AuthKit domain (e.g., "https://your-app.authkit.app")
8+
- AUTHKIT_DOMAIN: Your AuthKit domain (e.g., "https://your-app.authkit.app")
79
810
To run:
911
python server.py
@@ -16,10 +18,10 @@
1618

1719
auth = AuthKitProvider(
1820
authkit_domain=os.getenv("AUTHKIT_DOMAIN") or "",
19-
base_url="http://localhost:8000",
21+
base_url="http://127.0.0.1:8000",
2022
)
2123

22-
mcp = FastMCP("AuthKit DCR Example Server", auth=auth)
24+
mcp = FastMCP("AuthKit Example Server", auth=auth)
2325

2426

2527
@mcp.tool

examples/auth/authkit_dcr/README.md

Lines changed: 0 additions & 25 deletions
This file was deleted.

examples/auth/aws_oauth/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Demonstrates FastMCP server protection with AWS Cognito OAuth.
1010
- Create an App Client in your User Pool
1111
- Configure the App Client settings:
1212
- Enable "Authorization code grant" flow
13-
- Add Callback URL: `http://localhost:8000/auth/callback`
13+
- Add Callback URL: `http://127.0.0.1:8000/auth/callback`
1414
- Configure OAuth scopes (at minimum: `openid`)
1515
- Note your User Pool ID, App Client ID, Client Secret, and Cognito Domain Prefix
1616

examples/auth/aws_oauth/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from fastmcp.client import Client
1212

13-
SERVER_URL = "http://localhost:8000/mcp"
13+
SERVER_URL = "http://127.0.0.1:8000/mcp"
1414

1515

1616
async def main():

examples/auth/aws_oauth/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
or "eu-central-1",
3232
client_id=os.getenv("FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_ID") or "",
3333
client_secret=os.getenv("FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_SECRET") or "",
34-
base_url="http://localhost:8000",
34+
base_url="http://127.0.0.1:8000",
3535
# redirect_path="/custom/callback"
3636
)
3737

examples/auth/azure_oauth/README.md

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

examples/auth/azure_oauth/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
client_secret=os.getenv("FASTMCP_SERVER_AUTH_AZURE_CLIENT_SECRET") or "",
2525
tenant_id=os.getenv("FASTMCP_SERVER_AUTH_AZURE_TENANT_ID")
2626
or "", # Required for single-tenant apps - get from Azure Portal
27-
base_url="http://localhost:8000",
27+
base_url="http://127.0.0.1:8000",
2828
required_scopes=["read"],
2929
# required_scopes is automatically loaded from FASTMCP_SERVER_AUTH_AZURE_REQUIRED_SCOPES
3030
# At least one scope is required - use unprefixed scope names from your Azure App (e.g., ["read", "write"])

0 commit comments

Comments
 (0)