mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-09 07:09:11 +02:00
Add Keycloak OAuth Provider for Enterprise Authentication and local dev (#1937)
This commit is contained in:
parent
279b601f80
commit
99bf81c64f
10 changed files with 852 additions and 9 deletions
|
|
@ -1,2 +1,2 @@
|
|||
fastmcp
|
||||
python-dotenv
|
||||
python-dotenv
|
||||
|
|
|
|||
29
examples/auth/keycloak_oauth/README.md
Normal file
29
examples/auth/keycloak_oauth/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# Keycloak OAuth Example
|
||||
|
||||
Demonstrates FastMCP server protection with Keycloak OAuth.
|
||||
|
||||
**Requires Keycloak 26.6.0 or later** with Dynamic Client Registration enabled.
|
||||
|
||||
## 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/*`).
|
||||
|
||||
2. Set environment variables:
|
||||
|
||||
```bash
|
||||
export KEYCLOAK_REALM_URL="http://localhost:8080/realms/your-realm"
|
||||
```
|
||||
|
||||
3. Run the server:
|
||||
|
||||
```bash
|
||||
python server.py
|
||||
```
|
||||
|
||||
4. In another terminal, run the client:
|
||||
|
||||
```bash
|
||||
python client.py
|
||||
```
|
||||
|
||||
The client will open your browser for Keycloak authentication.
|
||||
33
examples/auth/keycloak_oauth/client.py
Normal file
33
examples/auth/keycloak_oauth/client.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
"""OAuth client example for connecting to a Keycloak-protected FastMCP server.
|
||||
|
||||
To run:
|
||||
python client.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from fastmcp import Client
|
||||
|
||||
SERVER_URL = "http://localhost:8000/mcp"
|
||||
|
||||
|
||||
async def main():
|
||||
async with Client(SERVER_URL, auth="oauth") as client:
|
||||
assert await client.ping()
|
||||
print("Successfully authenticated!")
|
||||
|
||||
tools = await client.list_tools()
|
||||
print(f"Available tools ({len(tools)}):")
|
||||
for tool in tools:
|
||||
print(f" - {tool.name}: {tool.description}")
|
||||
|
||||
print("Calling protected tool: get_access_token_claims")
|
||||
result = await client.call_tool("get_access_token_claims")
|
||||
claims = result.data
|
||||
print(f" sub: {claims.get('sub', 'N/A')}")
|
||||
print(f" scope: {claims.get('scope', 'N/A')}")
|
||||
print(f" azp: {claims.get('azp', 'N/A')}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
44
examples/auth/keycloak_oauth/server.py
Normal file
44
examples/auth/keycloak_oauth/server.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
"""Keycloak OAuth server example for FastMCP.
|
||||
|
||||
This example demonstrates how to protect a FastMCP server with Keycloak OAuth.
|
||||
|
||||
Required: Keycloak 26.6.0 or later with Dynamic Client Registration enabled.
|
||||
|
||||
To run:
|
||||
KEYCLOAK_REALM_URL=https://your-keycloak.com/realms/myrealm python server.py
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.auth.providers.keycloak import KeycloakAuthProvider
|
||||
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
|
||||
)
|
||||
|
||||
mcp = FastMCP("Keycloak Example Server", auth=auth)
|
||||
|
||||
|
||||
@mcp.tool
|
||||
def echo(message: str) -> str:
|
||||
"""Echo the provided message."""
|
||||
return message
|
||||
|
||||
|
||||
@mcp.tool
|
||||
async def get_access_token_claims() -> dict:
|
||||
"""Get the authenticated user's access token claims."""
|
||||
token = get_access_token()
|
||||
return {
|
||||
"sub": token.claims.get("sub"),
|
||||
"scope": token.claims.get("scope"),
|
||||
"azp": token.claims.get("azp"),
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run(transport="http", port=8000)
|
||||
Loading…
Add table
Add a link
Reference in a new issue