Most MCP server requires integration with authentication server, while the OAuth 2.1 protocol is still dynamic on it's own, a bare minimium implemention of it to secure your MCP remote server is crutial!
This is a complete, production-ready OAuth 2.0 server implementation with:
- Dynamic Client Registration (DCR) - RFC 7591 compliant
- Google OAuth Integration - Seamless Google authentication
- JWT Token Management - Secure access and refresh tokens
- Well-known Endpoints - OAuth 2.0 and OpenID Connect discovery
- CORS Support - Cross-origin resource sharing
- Supabase Storage - Scalable client and user data storage
- FastMCP Integration - Easy integration with MCP servers
- ✅ OAuth 2.0 Authorization Code Flow
- ✅ Dynamic Client Registration (DCR)
- ✅ Google OAuth 2.0 Integration
- ✅ JWT Access & Refresh Tokens
- ✅ Token Introspection & Revocation
- ✅ OpenID Connect Support
- ✅ Well-known Discovery Endpoints
- ✅ CORS Middleware
- ✅ User Context Management
- ✅ Supabase Database Integration
- ✅ FastMCP Server Integration
pip install -e .Create a .env file:
# Supabase Configuration
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your-supabase-anon-key
# Google OAuth Configuration
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# OAuth Server Configuration
OAUTH_SERVER_URL=http://localhost:8080
JWT_SECRET=your-jwt-secret-key
# Token Lifetime Configuration (optional)
ACCESS_TOKEN_LIFETIME=604800 # 7 days in seconds
REFRESH_TOKEN_LIFETIME=2592000 # 30 days in secondsRun the SQL schema in your Supabase project (see database_schema.sql).
oauth-standaloneoauth-serverfrom oauth_service.oauth_server import OAuthServer
# Start OAuth server
server = OAuthServer(host="0.0.0.0", port=8080)
server.run()from fastmcp import FastMCP
from oauth_service.auth.mcp_integration import setup_oauth_for_mcp
from oauth_service.auth.middleware import AuthMiddleware
# Create MCP server
mcp = FastMCP("My MCP Server")
# Setup OAuth integration
oauth_integration = setup_oauth_for_mcp(
mcp_instance=mcp,
oauth_server_url="http://localhost:8080"
)
# Add authentication middleware
mcp.add_middleware(AuthMiddleware, public_paths=["/health"])
# Your MCP tools here...
@mcp.tool()
async def protected_tool():
# This tool requires authentication
passGET /.well-known/oauth-authorization-server- OAuth 2.0 metadataGET /.well-known/openid_configuration- OpenID Connect configurationGET /.well-known/jwks.json- JSON Web Key Set
POST /oauth/register- Dynamic Client RegistrationGET /oauth/authorize- Authorization endpointPOST /oauth/token- Token endpointPOST /oauth/revoke- Token revocationPOST /oauth/introspect- Token introspectionGET /oauth/userinfo- User information
GET /health- Health check
import aiohttp
async def discover_oauth_server(oauth_server_url: str):
"""Discover OAuth 2.0 server configuration."""
discovery_url = f"{oauth_server_url}/.well-known/oauth-authorization-server"
async with aiohttp.ClientSession() as session:
async with session.get(discovery_url) as response:
config = await response.json()
return config
# Usage
oauth_config = await discover_oauth_server("http://localhost:8080")
authorization_endpoint = oauth_config["authorization_endpoint"]
token_endpoint = oauth_config["token_endpoint"]from fastmcp import FastMCP
from oauth_service.auth.mcp_integration import setup_oauth_for_mcp
from oauth_service.auth.middleware import AuthMiddleware
from starlette.responses import JSONResponse
# Create MCP server
mcp = FastMCP("My Protected Server")
# Setup OAuth integration
setup_oauth_for_mcp(mcp, oauth_server_url="http://localhost:8080")
mcp.add_middleware(AuthMiddleware, public_paths=["/.well-known/oauth-protected-resource"])
# Expose protected resource metadata
@mcp.get("/.well-known/oauth-protected-resource")
async def oauth_protected_resource():
return JSONResponse({
"resource_description": "My MCP Server API",
"scopes_supported": ["api:read", "api:write"],
"bearer_methods_supported": ["header"],
"authorization_server": "http://localhost:8080"
})
# Protected tool
@mcp.tool()
async def protected_tool() -> dict:
from oauth_service.auth.mcp_integration import user_context
user = user_context.get()
return {"message": f"Hello {user['name']}"}Register a new OAuth client:
curl -X POST http://localhost:8080/oauth/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "My Application",
"redirect_uris": ["http://localhost:3000/callback"],
"scope": "openid profile email"
}'- Client Registration: Register your application
- Authorization: Redirect users to
/oauth/authorize - Token Exchange: Exchange authorization code for tokens
- API Access: Use access token for protected resources
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ MCP Client │───▶│ OAuth Server │───▶│ Google OAuth │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ Supabase DB │
└─────────────────┘
- JWT Tokens: Cryptographically signed tokens
- Token Expiration: Configurable token lifetimes
- Secure Storage: Encrypted client secrets in Supabase
- CORS Protection: Configurable origin restrictions
- State Parameter: CSRF protection for authorization flow
MIT License - see LICENSE file for details.