Oauth Proxy Demo
Sample FastMCP server demonstrating OAuth Proxy pattern for Keycloak authentication without Dynamic Client Registration support
Ask AI about Oauth Proxy Demo
Powered by Claude Β· Grounded in docs
I know everything about Oauth Proxy Demo. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
FastMCP Keycloak OAuth Proxy Demo
A sample FastMCP server demonstrating the OAuth Proxy pattern for authenticating with Keycloak, a traditional OAuth provider that doesn't support Dynamic Client Registration (DCR).
Why OAuth Proxy?
MCP clients expect to use Dynamic Client Registration (DCR) - they want to register automatically and obtain credentials on the fly. However, Keycloak (like most traditional OAuth providers such as GitHub, Google, and Azure) requires manual app registration through an admin console.
The OAuth Proxy bridges this gap by:
- Presenting a DCR-compliant interface to MCP clients
- Using pre-registered Keycloak credentials behind the scenes
- Handling callback forwarding for dynamic client redirect URIs
- Issuing FastMCP JWT tokens instead of forwarding upstream tokens directly
This maintains proper OAuth 2.0 security boundaries while providing seamless MCP client integration.
Key Features Demonstrated
- OAuth Proxy Pattern: Bridges DCR-incompatible OAuth providers with MCP clients
- Dynamic Client Registration Emulation: Accepts client registration requests and returns pre-configured credentials
- Dual-PKCE Security: End-to-end PKCE at both client-to-proxy and proxy-to-upstream layers
- Token Factory Pattern: Issues FastMCP JWT tokens instead of forwarding upstream tokens
- Callback Forwarding: Supports dynamic client redirect URIs (random localhost ports, fixed URLs)
- JWT Token Verification: Validates tokens using Keycloak's JWKS endpoint
- Consent Screen: Protects against confused deputy attacks
- FastMCP Capabilities: Tools, resources, and prompts examples
Architecture
sequenceDiagram
participant Client as MCP Client
participant Proxy as FastMCP OAuthProxy
participant Keycloak as Keycloak OAuth Provider
participant User
Note over Client,Keycloak: Phase 1: Discovery & Registration
Client->>Proxy: 1. POST /mcp (initialize)
Proxy-->>Client: 401 Unauthorized + metadata URL
Client->>Proxy: 2. GET /.well-known/oauth-protected-resource/mcp
Proxy-->>Client: OAuth server metadata
Client->>Proxy: 3. POST /register (DCR with redirect_uri)
Note over Proxy: Records client redirect_uri<br/>Returns pre-configured credentials
Proxy-->>Client: client_id (fixed upstream credentials)
Note over Client,Keycloak: Phase 2: Authorization with Dual-PKCE
Client->>Proxy: 4. GET /authorize?code_challenge=...
Note over Proxy: Stores client PKCE challenge<br/>Generates own PKCE for upstream
Proxy-->>User: Show consent page
User->>Proxy: Approve client
Proxy->>Keycloak: Redirect to /authorize (proxy PKCE)
Keycloak-->>User: Login page
User->>Keycloak: Authenticate
Keycloak-->>Proxy: Authorization code
Note over Client,Keycloak: Phase 3: Token Exchange
Proxy->>Keycloak: POST /token (code + proxy verifier)
Keycloak-->>Proxy: Upstream access_token
Note over Proxy: Encrypts & stores upstream token<br/>Issues new FastMCP JWT
Proxy-->>Client: Redirect to client redirect_uri + code
Client->>Proxy: 5. POST /token (code + client verifier)
Note over Proxy: Validates client PKCE<br/>Returns FastMCP JWT
Proxy-->>Client: FastMCP JWT token
Note over Client,Keycloak: Phase 4: Authenticated Requests
Client->>Proxy: 6. POST /mcp (with FastMCP JWT)
Note over Proxy: Validates FastMCP JWT<br/>Verifies upstream token
Proxy-->>Client: Protected MCP resources
How It Works
-
The Problem: MCP clients expect Dynamic Client Registration (DCR) - they want to register automatically and get credentials on the fly. Keycloak requires manual app registration through its admin console.
-
The Solution: OAuthProxy presents a DCR-compliant interface to MCP clients while using your pre-registered Keycloak credentials behind the scenes.
-
The Flow:
- When a client registers, the proxy returns your fixed Keycloak credentials and stores the client's callback URL
- When a client authorizes, the proxy uses its fixed callback URL with Keycloak, then forwards back to the client's dynamic callback
- The proxy issues its own FastMCP JWT tokens (signed with HS256) instead of forwarding Keycloak tokens directly
- This maintains proper OAuth 2.0 audience boundaries and enables better security controls
Prerequisites
- Python 3.12+: Required for FastMCP
- Docker: For running Keycloak locally
- uv: Python package manager
- Install uv:
curl -LsSf https://astral.sh/uv/install.sh | sh - Or see uv installation docs
- Install uv:
Installation
1. Clone the Repository
git clone https://github.com/vikrantjain/mcp-oauth-proxy-demo.git
cd mcp-oauth-proxy-demo
2. Install Dependencies
uv sync
Configuration
1. Start Keycloak with Docker
docker run -d \
--name keycloak \
-p 8080:8080 \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:latest \
start-dev
Access Keycloak admin console at http://localhost:8080 (credentials: admin/admin)
2. Create a Client in Keycloak
- Navigate to Clients in the left sidebar
- Click Create client
- Configure the client:
- Client ID:
mcp_server - Client authentication: ON (for confidential client)
- Valid redirect URIs:
http://localhost:8000/auth/callback - Valid post logout redirect URIs:
http://localhost:8000
- Client ID:
- Save the client
- Go to the Credentials tab and copy the Client secret
3. Configure Environment Variables
cp .env.example .env
# Edit .env and add your Keycloak client secret
Update .env with your actual values:
KEYCLOAK_CLIENT_ID=mcp_server
KEYCLOAK_CLIENT_SECRET=<your-client-secret-from-keycloak>
KEYCLOAK_BASE_URL=http://localhost:8080
KEYCLOAK_REALM=master
MCP_SERVER_BASE_URL=http://localhost:8000
Running the Server
uv run fastmcp run mcp-server.py --transport streamable-http --host 0.0.0.0 --port 8000
The server will start on http://localhost:8000
Usage Examples
1. Python Client (FastMCP Client)
uv run python mcp-client.py
This client demonstrates:
- Calling the
greettool - Reading the
resource://server/configresource (OAuth configuration) - Getting the
explain_oauth_flowprompt
2. REST Client (VS Code REST Client Extension)
Install the REST Client extension for VS Code.
Use client-proxy.rest to test the complete OAuth Proxy flow with Dynamic Client Registration:
- Open
client-proxy.rest - Follow the step-by-step OAuth flow:
- Discovery and metadata retrieval
- Dynamic client registration
- Authorization with PKCE
- Token exchange
- Authenticated MCP requests
Note: client.rest contains unauthenticated requests for reference, but will fail since the server requires OAuth authentication.
Project Structure
.
βββ mcp-server.py # FastMCP server with OAuthProxy configuration
βββ mcp-client.py # Python client example using FastMCP Client
βββ client.rest # Simple MCP API tests (REST Client)
βββ client-proxy.rest # Complete OAuth flow demonstration
βββ pyproject.toml # Python project dependencies
βββ uv.lock # Dependency lock file
βββ .env.example # Environment variables template
βββ .env # Your actual environment variables (gitignored)
βββ .gitignore # Git ignore patterns
βββ .python-version # Python version specification (3.12)
βββ README.md # This file
Security Features
- Dual-PKCE: End-to-end PKCE at both client-to-proxy and proxy-to-upstream layers
- User Consent: Explicit approval required before client authorization
- Encrypted Token Storage: AES-128-CBC + HMAC-SHA256 encryption for stored tokens
- JWT Signature Validation: HS256 signature verification for FastMCP tokens
- Audience Validation: Prevents token misuse across different services
- Confused Deputy Protection: Consent screen prevents malicious client impersonation
Learn More
License
MIT License - See LICENSE file for details
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
