|
| 1 | +# Cognito DCR OAuth Integration Example |
| 2 | + |
| 3 | +This example demonstrates how to integrate the mcp-framework with the Cognito Dynamic Client Registration (DCR) implementation for OAuth 2.1 authentication. |
| 4 | + |
| 5 | +## Quick Start (5 minutes) |
| 6 | + |
| 7 | +### Step 1: Register OAuth Client |
| 8 | + |
| 9 | +From the cognito-dcr directory, register a new client: |
| 10 | + |
| 11 | +```bash |
| 12 | +cd ../../cognito-dcr/examples |
| 13 | +./quick-dcr-test.sh "MCP Test Server" "http://localhost:8080/oauth/callback" |
| 14 | +``` |
| 15 | + |
| 16 | +**Save the output** - you'll need the `CLIENT_ID` and `CLIENT_SECRET`. |
| 17 | + |
| 18 | +Example output: |
| 19 | +``` |
| 20 | +📋 Client Credentials |
| 21 | +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| 22 | +
|
| 23 | +Client ID: 1m3mpk6fioslohhl54the6ugoh |
| 24 | +Client Secret: prohg87lsuon3gnemk11ahkiu1kcnjsekghuesoideihh5m2dtu |
| 25 | +``` |
| 26 | + |
| 27 | +### Step 2: Configure Environment |
| 28 | + |
| 29 | +Create a `.env` file in the mcp-framework root directory: |
| 30 | + |
| 31 | +```bash |
| 32 | +cd ../../mcp-framework |
| 33 | +cp .env.example.cognito .env |
| 34 | +``` |
| 35 | + |
| 36 | +Edit `.env` and add your credentials: |
| 37 | + |
| 38 | +```env |
| 39 | +CLIENT_ID=1m3mpk6fioslohhl54the6ugoh |
| 40 | +CLIENT_SECRET=prohg87lsuon3gnemk11ahkiu1kcnjsekghuesoideihh5m2dtu |
| 41 | +
|
| 42 | +COGNITO_USER_POOL_ID=us-west-2_pJpps8NA4 |
| 43 | +COGNITO_REGION=us-west-2 |
| 44 | +COGNITO_DOMAIN=dcr-staging-78okmfo6 |
| 45 | +
|
| 46 | +MCP_SERVER_PORT=8080 |
| 47 | +MCP_RESOURCE_ID=https://mcp.example.com |
| 48 | +``` |
| 49 | + |
| 50 | +### Step 3: Run the Example |
| 51 | + |
| 52 | +```bash |
| 53 | +npx tsx examples/cognito-oauth-simple.ts |
| 54 | +``` |
| 55 | + |
| 56 | +You should see: |
| 57 | +``` |
| 58 | +🚀 Starting MCP Server with Cognito OAuth 2.1 |
| 59 | +
|
| 60 | +Configuration: |
| 61 | + Port: 8080 |
| 62 | + Region: us-west-2 |
| 63 | + User Pool: us-west-2_pJpps8NA4 |
| 64 | + Issuer: https://cognito-idp.us-west-2.amazonaws.com/us-west-2_pJpps8NA4 |
| 65 | + JWKS URI: https://cognito-idp.us-west-2.amazonaws.com/us-west-2_pJpps8NA4/.well-known/jwks.json |
| 66 | + Client ID: 1m3mpk6fioslohhl54the6ugoh |
| 67 | + Resource: https://mcp.example.com |
| 68 | +
|
| 69 | +✅ MCP Server started successfully! |
| 70 | +``` |
| 71 | + |
| 72 | +### Step 4: Test the Integration |
| 73 | + |
| 74 | +#### A. Check Metadata (No Auth Required) |
| 75 | + |
| 76 | +```bash |
| 77 | +curl http://localhost:8080/.well-known/oauth-protected-resource | jq |
| 78 | +``` |
| 79 | + |
| 80 | +Expected response: |
| 81 | +```json |
| 82 | +{ |
| 83 | + "resource": "https://mcp.example.com", |
| 84 | + "authorization_servers": [ |
| 85 | + "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_pJpps8NA4" |
| 86 | + ] |
| 87 | +} |
| 88 | +``` |
| 89 | + |
| 90 | +#### B. Get Access Token |
| 91 | + |
| 92 | +Using client credentials grant (service-to-service): |
| 93 | + |
| 94 | +```bash |
| 95 | +curl -X POST https://dcr-staging-78okmfo6.auth.us-west-2.amazoncognito.com/oauth2/token \ |
| 96 | + -H 'Content-Type: application/x-www-form-urlencoded' \ |
| 97 | + -u "1m3mpk6fioslohhl54the6ugoh:prohg87lsuon3gnemk11ahkiu1kcnjsekghuesoideihh5m2dtu" \ |
| 98 | + -d 'grant_type=client_credentials&scope=openid' | jq |
| 99 | +``` |
| 100 | + |
| 101 | +Save the `access_token` from the response. |
| 102 | + |
| 103 | +#### C. Call MCP Endpoint |
| 104 | + |
| 105 | +```bash |
| 106 | +curl -X POST http://localhost:8080/mcp \ |
| 107 | + -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ |
| 108 | + -H "Content-Type: application/json" \ |
| 109 | + -d '{ |
| 110 | + "jsonrpc": "2.0", |
| 111 | + "method": "tools/list", |
| 112 | + "id": 1 |
| 113 | + }' | jq |
| 114 | +``` |
| 115 | + |
| 116 | +Expected response: |
| 117 | +```json |
| 118 | +{ |
| 119 | + "jsonrpc": "2.0", |
| 120 | + "id": 1, |
| 121 | + "result": { |
| 122 | + "tools": [ |
| 123 | + { |
| 124 | + "name": "hello", |
| 125 | + "description": "Returns a greeting message", |
| 126 | + "inputSchema": { |
| 127 | + "type": "object", |
| 128 | + "properties": { |
| 129 | + "name": { |
| 130 | + "type": "string", |
| 131 | + "description": "Name to greet" |
| 132 | + } |
| 133 | + }, |
| 134 | + "required": ["name"] |
| 135 | + } |
| 136 | + } |
| 137 | + ] |
| 138 | + } |
| 139 | +} |
| 140 | +``` |
| 141 | + |
| 142 | +## What's Happening? |
| 143 | + |
| 144 | +1. **Dynamic Client Registration (DCR)**: The `quick-dcr-test.sh` script registers your application as an OAuth client with Cognito via the RFC 7591 DCR endpoint. |
| 145 | + |
| 146 | +2. **OAuth 2.1 Configuration**: The MCP server is configured to: |
| 147 | + - Accept access tokens from Cognito |
| 148 | + - Validate JWT signatures using Cognito's JWKS endpoint |
| 149 | + - Check audience claims match the client ID |
| 150 | + - Verify issuer claims match the Cognito User Pool |
| 151 | + |
| 152 | +3. **Token Validation**: When you call the MCP endpoint with a Bearer token: |
| 153 | + - The `OAuthAuthProvider` extracts the token from the Authorization header |
| 154 | + - Fetches the public key from the JWKS URI (cached for performance) |
| 155 | + - Validates the JWT signature, expiration, audience, and issuer |
| 156 | + - Allows or denies the request based on validation results |
| 157 | + |
| 158 | +## OAuth Grant Types |
| 159 | + |
| 160 | +### Client Credentials (Service-to-Service) |
| 161 | + |
| 162 | +Best for backend-to-backend communication where no user is involved. |
| 163 | + |
| 164 | +```bash |
| 165 | +# Get token |
| 166 | +curl -X POST https://dcr-staging-78okmfo6.auth.us-west-2.amazoncognito.com/oauth2/token \ |
| 167 | + -H 'Content-Type: application/x-www-form-urlencoded' \ |
| 168 | + -u "${CLIENT_ID}:${CLIENT_SECRET}" \ |
| 169 | + -d 'grant_type=client_credentials&scope=openid' |
| 170 | +``` |
| 171 | + |
| 172 | +### Authorization Code (User Context) |
| 173 | + |
| 174 | +For applications that need to authenticate users and act on their behalf. |
| 175 | + |
| 176 | +```bash |
| 177 | +# 1. Redirect user to authorization endpoint |
| 178 | +open "https://dcr-staging-78okmfo6.auth.us-west-2.amazoncognito.com/oauth2/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=http://localhost:8080/oauth/callback&scope=openid+email&state=random_state" |
| 179 | + |
| 180 | +# 2. After user signs in, Cognito redirects back with code |
| 181 | +# http://localhost:8080/oauth/callback?code=AUTHORIZATION_CODE&state=random_state |
| 182 | + |
| 183 | +# 3. Exchange code for token |
| 184 | +curl -X POST https://dcr-staging-78okmfo6.auth.us-west-2.amazoncognito.com/oauth2/token \ |
| 185 | + -H 'Content-Type: application/x-www-form-urlencoded' \ |
| 186 | + -u "${CLIENT_ID}:${CLIENT_SECRET}" \ |
| 187 | + -d "grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=http://localhost:8080/oauth/callback" |
| 188 | +``` |
| 189 | + |
| 190 | +## Cognito Endpoints Reference |
| 191 | + |
| 192 | +All endpoints for the staging DCR deployment: |
| 193 | + |
| 194 | +```typescript |
| 195 | +const COGNITO_CONFIG = { |
| 196 | + // DCR Registration |
| 197 | + registrationEndpoint: "https://7a03vnsj7i.execute-api.us-west-2.amazonaws.com/.well-known/oauth-registration", |
| 198 | + |
| 199 | + // Authorization Server Metadata |
| 200 | + metadataEndpoint: "https://7a03vnsj7i.execute-api.us-west-2.amazonaws.com/.well-known/oauth-authorization-server", |
| 201 | + |
| 202 | + // Cognito OAuth Endpoints |
| 203 | + issuer: "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_pJpps8NA4", |
| 204 | + authorizationEndpoint: "https://dcr-staging-78okmfo6.auth.us-west-2.amazoncognito.com/oauth2/authorize", |
| 205 | + tokenEndpoint: "https://dcr-staging-78okmfo6.auth.us-west-2.amazoncognito.com/oauth2/token", |
| 206 | + jwksUri: "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_pJpps8NA4/.well-known/jwks.json", |
| 207 | + |
| 208 | + // User Pool Details |
| 209 | + userPoolId: "us-west-2_pJpps8NA4", |
| 210 | + region: "us-west-2", |
| 211 | + domain: "dcr-staging-78okmfo6" |
| 212 | +}; |
| 213 | +``` |
| 214 | + |
| 215 | +## Creating Test Users |
| 216 | + |
| 217 | +For testing the authorization code flow, you need Cognito users: |
| 218 | + |
| 219 | +```bash |
| 220 | +# Create user |
| 221 | +aws cognito-idp admin-create-user \ |
| 222 | + --user-pool-id us-west-2_pJpps8NA4 \ |
| 223 | + |
| 224 | + --user-attributes Name=email, [email protected] Name=email_verified,Value=true \ |
| 225 | + --temporary-password TempPass123! \ |
| 226 | + --message-action SUPPRESS |
| 227 | + |
| 228 | +# Set permanent password |
| 229 | +aws cognito-idp admin-set-user-password \ |
| 230 | + --user-pool-id us-west-2_pJpps8NA4 \ |
| 231 | + |
| 232 | + --password MyPassword123! \ |
| 233 | + --permanent |
| 234 | +``` |
| 235 | + |
| 236 | +## Troubleshooting |
| 237 | + |
| 238 | +### "Invalid token signature" |
| 239 | + |
| 240 | +**Cause**: JWKS URI incorrect or network issues |
| 241 | + |
| 242 | +**Solution**: Verify JWKS endpoint is accessible: |
| 243 | +```bash |
| 244 | +curl https://cognito-idp.us-west-2.amazonaws.com/us-west-2_pJpps8NA4/.well-known/jwks.json |
| 245 | +``` |
| 246 | + |
| 247 | +### "Token audience invalid" |
| 248 | + |
| 249 | +**Cause**: Token's `aud` claim doesn't match CLIENT_ID |
| 250 | + |
| 251 | +**Solution**: Ensure the token was issued for your client ID: |
| 252 | +```bash |
| 253 | +# Decode token to check audience |
| 254 | +echo "YOUR_TOKEN" | cut -d. -f2 | base64 -d | jq '.aud' |
| 255 | +``` |
| 256 | + |
| 257 | +### "Authorization header missing" |
| 258 | + |
| 259 | +**Cause**: Not sending Bearer token |
| 260 | + |
| 261 | +**Solution**: Always include Authorization header: |
| 262 | +```bash |
| 263 | +curl -H "Authorization: Bearer YOUR_TOKEN" ... |
| 264 | +``` |
| 265 | + |
| 266 | +## Additional Resources |
| 267 | + |
| 268 | +- [Cognito DCR Integration Guide](../../cognito-dcr/docs/MCP_FRAMEWORK_INTEGRATION.md) |
| 269 | +- [Cognito DCR Testing Guide](../../cognito-dcr/docs/TESTING_GUIDE.md) |
| 270 | +- [MCP Framework OAuth Documentation](../docs/OAUTH.md) |
| 271 | +- [RFC 7591 - Dynamic Client Registration](https://tools.ietf.org/html/rfc7591) |
| 272 | +- [RFC 8414 - Authorization Server Metadata](https://www.rfc-editor.org/rfc/rfc8414.html) |
| 273 | +- [MCP Authorization Spec](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) |
0 commit comments