Skip to content

Commit 5486b5a

Browse files
Add AWS Cognito OAuth Provider for Enterprise Authentication (#1873)
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
1 parent fccd081 commit 5486b5a

13 files changed

Lines changed: 962 additions & 7 deletions

File tree

docs/docs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@
168168
"pages": [
169169
"integrations/auth0",
170170
"integrations/authkit",
171+
"integrations/aws-cognito",
171172
"integrations/azure",
172173
"integrations/descope",
173174
"integrations/github",

docs/integrations/aws-cognito.mdx

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
---
2+
title: AWS Cognito OAuth 🤝 FastMCP
3+
sidebarTitle: AWS Cognito
4+
description: Secure your FastMCP server with AWS Cognito user pools
5+
icon: aws
6+
tag: NEW
7+
---
8+
9+
import { VersionBadge } from "/snippets/version-badge.mdx"
10+
11+
<VersionBadge version="2.12.4" />
12+
13+
This guide shows you how to secure your FastMCP server using **AWS Cognito user pools**. Since AWS Cognito doesn't support Dynamic Client Registration, this integration uses the [**OAuth Proxy**](/servers/auth/oauth-proxy) pattern to bridge AWS Cognito's traditional OAuth with MCP's authentication requirements. It also includes robust JWT token validation, ensuring enterprise-grade authentication.
14+
15+
## Configuration
16+
17+
### Prerequisites
18+
19+
Before you begin, you will need:
20+
1. An **[AWS Account](https://aws.amazon.com/)** with access to create AWS Cognito user pools
21+
2. Basic familiarity with AWS Cognito concepts (user pools, app clients)
22+
3. Your FastMCP server's URL (can be localhost for development, e.g., `http://localhost:8000`)
23+
24+
### Step 1: Create an AWS Cognito User Pool and App Client
25+
26+
Set up AWS Cognito user pool with an app client to get the credentials needed for authentication:
27+
28+
<Steps>
29+
<Step title="Navigate to AWS Cognito">
30+
Go to the **[AWS Cognito Console](https://console.aws.amazon.com/cognito/)** and ensure you're in your desired AWS region.
31+
32+
Select **"User pools"** from the side navigation (click on the hamburger icon at the top left in case you don't see any), and click **"Create user pool"** to create a new user pool.
33+
</Step>
34+
35+
<Step title="Define Your Application">
36+
AWS Cognito now provides a streamlined setup experience:
37+
38+
1. **Application type**: Select **"Traditional web application"** (this is the correct choice for FastMCP server-side authentication)
39+
2. **Name your application**: Enter a descriptive name (e.g., `FastMCP Server`)
40+
41+
The traditional web application type automatically configures:
42+
- Server-side authentication with client secrets
43+
- Authorization code grant flow
44+
- Appropriate security settings for confidential clients
45+
46+
<Info>
47+
Choose "Traditional web application" rather than SPA, Mobile app, or Machine-to-machine options. This ensures proper OAuth 2.0 configuration for FastMCP.
48+
</Info>
49+
</Step>
50+
51+
<Step title="Configure Options">
52+
AWS will guide you through configuration options:
53+
54+
- **Sign-in identifiers**: Choose how users will sign in (email, username, or phone)
55+
- **Required attributes**: Select any additional user information you need
56+
- **Return URL**: Add your callback URL (e.g., `http://localhost:8000/auth/callback` for development)
57+
58+
<Tip>
59+
The simplified interface handles most OAuth security settings automatically based on your application type selection.
60+
</Tip>
61+
</Step>
62+
63+
<Step title="Review and Create">
64+
Review your configuration and click **"Create user pool"**.
65+
66+
After creation, you'll see your user pool details. Save these important values:
67+
- **User pool ID** (format: `eu-central-1_XXXXXXXXX`)
68+
- **Client ID** (found under → "Applications" → "App clients" in the side navigation → \<Your application name, e.g., `FastMCP Server`\> → "App client information")
69+
- **Client Secret** (found under → "Applications" → "App clients" in the side navigation → \<Your application name, e.g., `FastMCP Server`\> → "App client information")
70+
71+
<Tip>
72+
The user pool ID and app client credentials are all you need for FastMCP configuration.
73+
</Tip>
74+
</Step>
75+
76+
<Step title="Configure OAuth Settings">
77+
Under "Login pages" in your app client's settings, you can double check and adjust the OAuth configuration:
78+
79+
- **Allowed callback URLs**: Add your server URL + `/auth/callback` (e.g., `http://localhost:8000/auth/callback`)
80+
- **Allowed sign-out URLs**: Optional, for logout functionality
81+
- **OAuth 2.0 grant types**: Ensure "Authorization code grant" is selected
82+
- **OpenID Connect scopes**: Select scopes your application needs (e.g., `openid`, `email`, `profile`)
83+
84+
<Tip>
85+
For local development, you can use `http://localhost` URLs. For production, you must use HTTPS.
86+
</Tip>
87+
</Step>
88+
89+
<Step title="Pick Up AWS Cognito Domain">
90+
Navigate to **"Branding" → "Domain"** in the side navigation to find or configure Your AWS Cognito domain:
91+
92+
**Option 1: Use Auto-Generated Domain**
93+
- If AWS has already created a domain automatically, note the **domain prefix** (the part before `.auth.region.amazoncognito.com`)
94+
- This prefix is what you'll use in your FastMCP configuration
95+
96+
**Option 2: Create a Custom Domain Prefix**
97+
- If no domain exists or you want a better name, delete the existing domain and create a new one using the **"Actions"** menu
98+
- Under **"Domain"****"Cognito domain"** in the **"Create Cognito domain"** dialog, enter a meaningful prefix (e.g., `my-app`) that is available in the AWS region you are in
99+
- Just note the **domain prefix** you entered (e.g., `my-fastmcp-app`) - this is what you'll use in your FastMCP configuration
100+
101+
<Info>
102+
The FastMCP AWS Cognito provider automatically constructs the full domain from your prefix and region, simplifying configuration.
103+
</Info>
104+
</Step>
105+
106+
<Step title="Save Your Credentials">
107+
After setup, you'll have:
108+
109+
- **User Pool ID**: Format like `eu-central-1_XXXXXXXXX`
110+
- **Client ID**: Your application's client identifier
111+
- **Client Secret**: Generated client secret (keep secure)
112+
- **Domain Prefix**: The prefix of Your AWS Cognito domain
113+
- **AWS Region**: Where Your AWS Cognito user pool is located
114+
115+
<Tip>
116+
Store these credentials securely. Never commit them to version control. Use environment variables or AWS Secrets Manager in production.
117+
</Tip>
118+
</Step>
119+
</Steps>
120+
121+
### Step 2: FastMCP Configuration
122+
123+
Create your FastMCP server using the `AWSCognitoProvider`, which handles AWS Cognito's JWT tokens and user claims automatically:
124+
125+
```python server.py
126+
from fastmcp import FastMCP
127+
from fastmcp.server.auth.providers.aws import AWSCognitoProvider
128+
from fastmcp.server.dependencies import get_access_token
129+
130+
# The AWSCognitoProvider handles JWT validation and user claims
131+
auth_provider = AWSCognitoProvider(
132+
user_pool_id="eu-central-1_XXXXXXXXX", # Your AWS Cognito user pool ID
133+
aws_region="eu-central-1", # AWS region (defaults to eu-central-1)
134+
client_id="your-app-client-id", # Your app client ID
135+
client_secret="your-app-client-secret", # Your app client Secret
136+
base_url="http://localhost:8000", # Must match your callback URL
137+
# redirect_path="/auth/callback" # Default value, customize if needed
138+
)
139+
140+
mcp = FastMCP(name="AWS Cognito Secured App", auth=auth_provider)
141+
142+
# Add a protected tool to test authentication
143+
@mcp.tool
144+
async def get_access_token_claims() -> dict:
145+
"""Get the authenticated user's access token claims."""
146+
token = get_access_token()
147+
return {
148+
"sub": token.claims.get("sub"),
149+
"username": token.claims.get("username"),
150+
"cognito:groups": token.claims.get("cognito:groups", []),
151+
}
152+
```
153+
154+
## Testing
155+
156+
### Running the Server
157+
158+
Start your FastMCP server with HTTP transport to enable OAuth flows:
159+
160+
```bash
161+
fastmcp run server.py --transport http --port 8000
162+
```
163+
164+
Your server is now running and protected by AWS Cognito OAuth authentication.
165+
166+
### Testing with a Client
167+
168+
Create a test client that authenticates with Your AWS Cognito-protected server:
169+
170+
```python test_client.py
171+
from fastmcp import Client
172+
import asyncio
173+
174+
async def main():
175+
# The client will automatically handle AWS Cognito OAuth
176+
async with Client("http://localhost:8000/mcp/", auth="oauth") as client:
177+
# First-time connection will open AWS Cognito login in your browser
178+
print("✓ Authenticated with AWS Cognito!")
179+
180+
# Test the protected tool
181+
print("Calling protected tool: get_access_token_claims")
182+
result = await client.call_tool("get_access_token_claims")
183+
user_data = result.data
184+
print("Available access token claims:")
185+
print(f"- sub: {user_data.get('sub', 'N/A')}")
186+
print(f"- username: {user_data.get('username', 'N/A')}")
187+
print(f"- cognito:groups: {user_data.get('cognito:groups', [])}")
188+
189+
if __name__ == "__main__":
190+
asyncio.run(main())
191+
```
192+
193+
When you run the client for the first time:
194+
1. Your browser will open to AWS Cognito's hosted UI login page
195+
2. After you sign in (or sign up), you'll be redirected back to your MCP server
196+
3. The client receives the JWT token and can make authenticated requests
197+
198+
<Info>
199+
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.
200+
</Info>
201+
202+
## Environment Variables
203+
204+
For production deployments, use environment variables instead of hardcoding credentials.
205+
206+
### Provider Selection
207+
208+
Setting this environment variable allows the AWS Cognito provider to be used automatically without explicitly instantiating it in code.
209+
210+
<Card>
211+
<ParamField path="FASTMCP_SERVER_AUTH" default="Not set">
212+
Set to `fastmcp.server.auth.providers.aws.AWSCognitoProvider` to use AWS Cognito authentication.
213+
</ParamField>
214+
</Card>
215+
216+
### AWS Cognito-Specific Configuration
217+
218+
These environment variables provide default values for the AWS Cognito provider, whether it's instantiated manually or configured via `FASTMCP_SERVER_AUTH`.
219+
220+
<Card>
221+
<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_USER_POOL_ID" required>
222+
Your AWS Cognito user pool ID (e.g., `eu-central-1_XXXXXXXXX`)
223+
</ParamField>
224+
225+
<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_AWS_REGION" default="eu-central-1">
226+
AWS region where your AWS Cognito user pool is located
227+
</ParamField>
228+
229+
<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_ID" required>
230+
Your AWS Cognito app client ID
231+
</ParamField>
232+
233+
<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_SECRET" required>
234+
Your AWS Cognito app client secret
235+
</ParamField>
236+
237+
<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_BASE_URL" default="http://localhost:8000">
238+
Public URL of your FastMCP server for OAuth callbacks
239+
</ParamField>
240+
241+
<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_REDIRECT_PATH" default="/auth/callback">
242+
One of the redirect paths configured in your AWS Cognito app client
243+
</ParamField>
244+
245+
<ParamField path="FASTMCP_SERVER_AUTH_AWS_COGNITO_REQUIRED_SCOPES" default='["openid"]'>
246+
Comma-, space-, or JSON-separated list of required OAuth scopes (e.g., `openid email` or `["openid","email","profile"]`)
247+
</ParamField>
248+
</Card>
249+
250+
Example `.env` file:
251+
```bash
252+
# Use the AWS Cognito provider
253+
FASTMCP_SERVER_AUTH=fastmcp.server.auth.providers.aws.AWSCognitoProvider
254+
255+
# AWS Cognito credentials
256+
FASTMCP_SERVER_AUTH_AWS_COGNITO_USER_POOL_ID=eu-central-1_XXXXXXXXX
257+
FASTMCP_SERVER_AUTH_AWS_COGNITO_AWS_REGION=eu-central-1
258+
FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_ID=your-app-client-id
259+
FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_SECRET=your-app-client-secret
260+
FASTMCP_SERVER_AUTH_AWS_COGNITO_BASE_URL=https://your-server.com
261+
FASTMCP_SERVER_AUTH_AWS_COGNITO_REQUIRED_SCOPES=openid,email,profile
262+
```
263+
264+
With environment variables set, your server code simplifies to:
265+
266+
```python server.py
267+
from fastmcp import FastMCP
268+
from fastmcp.server.dependencies import get_access_token
269+
270+
# Authentication is automatically configured from environment
271+
mcp = FastMCP(name="AWS Cognito Secured App")
272+
273+
@mcp.tool
274+
async def get_access_token_claims() -> dict:
275+
"""Get the authenticated user's access token claims."""
276+
token = get_access_token()
277+
return {
278+
"sub": token.claims.get("sub"),
279+
"username": token.claims.get("username"),
280+
"cognito:groups": token.claims.get("cognito:groups", []),
281+
}
282+
```
283+
284+
## Features
285+
286+
### JWT Token Validation
287+
288+
The AWS Cognito provider includes robust JWT token validation:
289+
290+
- **Signature Verification**: Validates tokens against AWS Cognito's public keys (JWKS)
291+
- **Expiration Checking**: Automatically rejects expired tokens
292+
- **Issuer Validation**: Ensures tokens come from your specific AWS Cognito user pool
293+
- **Scope Enforcement**: Verifies required OAuth scopes are present
294+
295+
### User Claims and Groups
296+
297+
Access rich user information from AWS Cognito JWT tokens:
298+
299+
```python
300+
from fastmcp.server.dependencies import get_access_token
301+
302+
@mcp.tool
303+
async def admin_only_tool() -> str:
304+
"""A tool only available to admin users."""
305+
token = get_access_token()
306+
user_groups = token.claims.get("cognito:groups", [])
307+
308+
if "admin" not in user_groups:
309+
raise ValueError("This tool requires admin access")
310+
311+
return "Admin access granted!"
312+
```
313+
314+
### Enterprise Integration
315+
316+
Perfect for enterprise environments with:
317+
318+
- **Single Sign-On (SSO)**: Integrate with corporate identity providers
319+
- **Multi-Factor Authentication (MFA)**: Leverage AWS Cognito's built-in MFA
320+
- **User Groups**: Role-based access control through AWS Cognito groups
321+
- **Custom Attributes**: Access custom user attributes defined in your AWS Cognito user pool
322+
- **Compliance**: Meet enterprise security and compliance requirements

docs/servers/auth/authentication.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ This example uses WorkOS AuthKit as the external identity provider. The `AuthKit
127127

128128
<VersionBadge version="2.12.0" />
129129

130-
`OAuthProxy` enables authentication with OAuth providers that **don't support Dynamic Client Registration (DCR)**, such as GitHub, Google, Azure, and most traditional enterprise identity systems.
130+
`OAuthProxy` enables authentication with OAuth providers that **don't support Dynamic Client Registration (DCR)**, such as GitHub, Google, Azure, AWS, and most traditional enterprise identity systems.
131131

132132
When identity providers require manual app registration and fixed credentials, `OAuthProxy` bridges the gap. It presents a DCR-compliant interface to MCP clients (accepting any registration request) while using your pre-registered credentials with the upstream provider. The proxy handles the complexity of callback forwarding, enabling dynamic client callbacks to work with providers that require fixed redirect URIs.
133133

@@ -256,7 +256,7 @@ This approach simplifies deployment pipelines and follows twelve-factor app prin
256256

257257
The authentication approach you choose depends on your existing infrastructure, security requirements, and operational constraints.
258258

259-
**For OAuth providers without DCR support (GitHub, Google, Azure, most enterprise systems), use OAuth Proxy.** These providers require manual app registration through their developer consoles. OAuth Proxy bridges the gap by presenting a DCR-compliant interface to MCP clients while using your fixed credentials with the provider. The proxy's callback forwarding pattern enables dynamic client ports to work with providers that require fixed redirect URIs.
259+
**For OAuth providers without DCR support (GitHub, Google, Azure, AWS, most enterprise systems), use OAuth Proxy.** These providers require manual app registration through their developer consoles. OAuth Proxy bridges the gap by presenting a DCR-compliant interface to MCP clients while using your fixed credentials with the provider. The proxy's callback forwarding pattern enables dynamic client ports to work with providers that require fixed redirect URIs.
260260

261261
**For identity providers with DCR support (Descope, WorkOS AuthKit, modern auth platforms), use RemoteAuthProvider.** These providers allow clients to dynamically register and obtain credentials without manual configuration. This enables the fully automated authentication flow that MCP is designed for, providing the best user experience and simplest implementation.
262262

docs/servers/auth/oauth-proxy.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { VersionBadge } from "/snippets/version-badge.mdx";
1010

1111
<VersionBadge version="2.12.0" />
1212

13-
OAuth Proxy enables FastMCP servers to authenticate with OAuth providers that **don't support Dynamic Client Registration (DCR)**. This includes virtually all traditional OAuth providers: GitHub, Google, Azure, Discord, Facebook, and most enterprise identity systems. For providers that do support DCR (like Descope and WorkOS AuthKit), use [`RemoteAuthProvider`](/servers/auth/remote-oauth) instead.
13+
OAuth Proxy enables FastMCP servers to authenticate with OAuth providers that **don't support Dynamic Client Registration (DCR)**. This includes virtually all traditional OAuth providers: GitHub, Google, Azure, AWS, Discord, Facebook, and most enterprise identity systems. For providers that do support DCR (like Descope and WorkOS AuthKit), use [`RemoteAuthProvider`](/servers/auth/remote-oauth) instead.
1414

1515
MCP clients expect to register automatically and obtain credentials on the fly, but traditional providers require manual app registration through their developer consoles. OAuth Proxy bridges this gap by presenting a DCR-compliant interface to MCP clients while using your pre-registered credentials with the upstream provider. When a client attempts to register, the proxy returns your fixed credentials. When a client initiates authorization, the proxy handles the complexity of callback forwarding—storing the client's dynamic callback URL, using its own fixed callback with the provider, then forwarding back to the client after token exchange.
1616

@@ -136,7 +136,7 @@ mcp = FastMCP(name="My Server", auth=auth)
136136
PKCE parameters to send upstream while separately validating the client's
137137
PKCE. This ensures end-to-end PKCE security at both layers (client-to-proxy
138138
and proxy-to-upstream). - `True` (default): Forward PKCE for providers that
139-
support it (Google, Azure, GitHub, etc.) - `False`: Disable only if upstream
139+
support it (Google, Azure, AWS, GitHub, etc.) - `False`: Disable only if upstream
140140
provider doesn't support PKCE
141141
</ParamField>
142142

docs/servers/auth/oidc-proxy.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { VersionBadge } from "/snippets/version-badge.mdx";
1010

1111
<VersionBadge version="2.12.4" />
1212

13-
OIDC Proxy enables FastMCP servers to authenticate with OIDC providers that **don't support Dynamic Client Registration (DCR)** out of the box. This includes OAuth providers like: Auth0, Google, Azure, etc. For providers that do support DCR (like WorkOS AuthKit), use [`RemoteAuthProvider`](/servers/auth/remote-oauth) instead.
13+
OIDC Proxy enables FastMCP servers to authenticate with OIDC providers that **don't support Dynamic Client Registration (DCR)** out of the box. This includes OAuth providers like: Auth0, Google, Azure, AWS, etc. For providers that do support DCR (like WorkOS AuthKit), use [`RemoteAuthProvider`](/servers/auth/remote-oauth) instead.
1414

1515
The OIDC Proxy is built upon [`OAuthProxy`](/servers/auth/oauth-proxy) so it has all the same functionality under the covers.
1616

docs/servers/auth/remote-oauth.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Remote OAuth integration allows your FastMCP server to leverage external identit
1515
<Tip>
1616
**When to use RemoteAuthProvider vs OAuth Proxy:**
1717
- **RemoteAuthProvider**: For providers WITH Dynamic Client Registration (Descope, WorkOS AuthKit, modern OIDC providers)
18-
- **OAuth Proxy**: For providers WITHOUT Dynamic Client Registration (GitHub, Google, Azure, Discord, etc.)
18+
- **OAuth Proxy**: For providers WITHOUT Dynamic Client Registration (GitHub, Google, Azure, AWS, Discord, etc.)
1919

2020
RemoteAuthProvider requires DCR support for fully automated client registration and authentication.
2121
</Tip>

0 commit comments

Comments
 (0)