Oauth Example
Minimal example of an OAuth 2.1 Authorization Server (FastAPI) and a separate Resource Server (FastMCP) aligned with MCP protocol revision 2025‑06‑18
Ask AI about Oauth Example
Powered by Claude · Grounded in docs
I know everything about Oauth Example. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
MCP OAuth example (separate Authorization Server and Resource Server)
Minimal, non‑production example of an OAuth 2.1 Authorization Server (FastAPI) and a separate Resource Server (FastMCP) aligned with MCP protocol revision 2025‑06‑18, which requires the authorization server to be separate from the resource server.
- Authorization flow: Authorization Code + PKCE (S256)
- Tokens: JWT access tokens (RS256) with JWKS discovery
- Resource server: validates
iss,aud, signature, and required scopes - Dynamic client registration enabled on the authorization server
This is for learning and inspection only. Storage is in memory, keys are generated on start, and nothing is persisted.
Components
auth_server/— FastAPI OAuth authorization server- Well-known metadata, dynamic client registration,
/authorize,/token,/oauth/jwks - In-memory users and consents
- Well-known metadata, dynamic client registration,
mcp_server/— FastMCP resource server- Uses
fastmcpwithOAuthProviderandJWTVerifier - Exposes a trivial tool: “Greet someone”
- Uses
Requirements
- Python 3.12+
uv(for dependency management and running)
Running
Authorization server (default http://localhost:8999):
cd auth_server
uv sync
uv run uvicorn src.app:app --host 0.0.0.0 --port 8999
Resource server (default http://localhost:8990):
cd mcp_server
uv sync
uv run python -m src.server
Configuration
Both services read a local .env file in their own directories. For testing you don't need to change anything, there are default values for all variables.
Authorization server (auth_server/src/config.py, prefix AUTH_SERVER_):
AUTH_SERVER_ISSUER(defaulthttp://localhost:8999)AUTH_SERVER_RESOURCE(defaulthttp://localhost:8990)AUTH_SERVER_KNOWN_RESOURCES(defaults toRESOURCEif not set)AUTH_SERVER_SESSION_SECRET(change from the dev default)- TTLs:
AUTH_SERVER_ACCESS_TOKEN_TTL_SECONDS(3600),AUTH_SERVER_AUTH_CODE_TTL_SECONDS(600)
Resource server (mcp_server/src/config.py):
AUTHORIZATION_SERVER_URL(defaulthttp://localhost:8999)RESOURCE_SERVER_URL(defaulthttp://localhost:8990)JWKS_ENDPOINT(default/oauth/jwks)REQUIRED_SCOPES(defaultmcp.read,mcp.write)
Auth server endpoints (summary)
GET /.well-known/oauth-authorization-server— metadataPOST /register— dynamic client registrationGET /oauth/jwks— JWKS (public keys)GET,POST /authorize— authorization endpoint (code + PKCE)POST /token— token endpoint (JWT access tokens)GET,POST /login— simple form login (in-memory users)
Demo data
- Users:
alice/password123,bob/hunter2 - Scopes:
mcp.read,mcp.write
Testing with an MCP protocol inspector
- Start both servers as above.
- In the inspector, type URL
http://localhost:8990and select streamable HTTP transport type (left sidebar). - Click "Open Auth Settings" (area in the middle of the screen).
- You can go either with Quick OAuth Flow or with Guided (in which you will go step by step by clicking on the Continue button).
- In the process you will be redirected to the authorization server to login. Use a demo user, approve requested scopes, and you’ll be redirected back.
- You should reach "Authentication Complete" step.
Notes and limitations
- In-memory storage for users, clients, auth codes, and consents. Restart clears everything, including dynamic client registrations.
- RSA keys are generated on startup; JWKS changes on restart.
- Session cookie is
HttpOnlyandSecure; in pure HTTP setups some browsers won’t store it. - No refresh tokens, no DB, no migrations, no hardening. Intended only for exploration and protocol inspection.
