R167/mcp-oauth
If you are the rightful owner of mcp-oauth and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
The MCP OAuth Authorization Server is a robust, production-ready OAuth 2.1/OIDC authorization server designed to secure Model Context Protocol (MCP) resources, leveraging Cloudflare Workers for deployment.
MCP OAuth Authorization Server
A production-ready OAuth 2.1/OIDC authorization server built on Cloudflare Workers for securing Model Context Protocol (MCP) resources. The server implements 2-hop authentication via GitHub with comprehensive security features.
Features
- OAuth 2.1 Compliant: Authorization Code flow with PKCE
- GitHub Integration: 2-hop authentication via GitHub OAuth
- MCP Scope Validation: Fine-grained access control for MCP servers
- Security: JWT tokens, encrypted refresh tokens, PKCE enforcement
- Cloudflare Workers: Serverless deployment with D1 database storage
- Standards Compliance: OAuth 2.1, OIDC Discovery, JWKS
Architecture
See for detailed architecture documentation.
Quick Start
Development
# Install dependencies
pnpm install
# Start development server
pnpm run dev
Server runs on http://localhost:8787
with auto-generated test keys.
Staging Deployment (Ready to Use!)
The project includes a pre-configured staging environment:
# 1. Set up secrets (interactive script)
./scripts/setup-secrets.sh staging
# 2. Deploy to staging
pnpm run deploy:staging
# 3. Test deployment
curl https://mcp-oauth-authorization-server-staging.wmdurand.workers.dev/health
Staging URL: https://mcp-oauth-authorization-server-staging.wmdurand.workers.dev
Note: You must configure secrets before the server will work properly.
Production Deployment
# 1. Set up production secrets
./scripts/setup-secrets.sh prod
# 2. Deploy to production
pnpm run deploy:prod
Production URL: https://auth.mcp.r167.dev
Configuration
GitHub OAuth App Setup
Create a GitHub OAuth App with these settings:
- Staging callback:
https://mcp-oauth-authorization-server-staging.wmdurand.workers.dev/auth/github/callback
- Production callback:
https://auth.mcp.r167.dev/auth/github/callback
MCP Servers
Configure your MCP servers in src/config.json
(production) or src/config.staging.json
(staging):
{
"servers": {
"your-domain.com": {
"your-server": {
"name": "Your MCP Server",
"description": "Description of what this server provides",
"allowed_users": ["github-username1", "github-username2"]
}
}
}
}
Required Configuration
Cloudflare Secrets
Variable | Description |
---|---|
GITHUB_CLIENT_ID | GitHub OAuth app client ID |
GITHUB_CLIENT_SECRET | GitHub OAuth app client secret |
JWT_PRIVATE_KEY | RS256 private key for JWT signing |
JWT_PUBLIC_KEY | RS256 public key for JWT verification |
REFRESH_ENCRYPTION_KEY | AES-256 key for refresh token encryption |
Environment Variables
Variable | Description | Set in |
---|---|---|
WORKER_BASE_URL | Full URL of the deployed worker | wrangler.jsonc |
Development
# Start development server
pnpm run dev
# Run tests
pnpm test
# Type checking
pnpm run type-check
# Format code
pnpm run format
Automated Secret Setup
Use the provided script to easily configure all required secrets:
# For staging environment
./scripts/setup-secrets.sh staging
# For production environment
./scripts/setup-secrets.sh prod
The script will:
- Prompt for GitHub OAuth credentials
- Auto-generate JWT key pair (or accept manual input)
- Auto-generate refresh token encryption key (or accept manual input)
- Configure all secrets automatically
Usage
OAuth Flow
- Authorization Request: Client redirects user to
/authorize
with PKCE parameters - GitHub Authentication: User authenticates with GitHub
- Scope Validation: Server validates MCP scope and user permissions
- Consent Screen: User approves access (skipped if previously approved)
- Authorization Code: Server returns authorization code to client
- Token Exchange: Client exchanges code for access/refresh tokens using PKCE verifier
Client Registration
All OAuth clients must be registered before use via the dynamic client registration endpoint:
curl -X POST https://auth.mcp.r167.dev/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "My MCP Client",
"redirect_uris": ["https://example.com/callback"],
"scope": "mcp:example.com:github-tools email"
}'
Response:
{
"client_id": "mcp_example.com_12345...",
"client_name": "My MCP Client",
"redirect_uris": ["https://example.com/callback"],
"scope": "mcp:example.com:github-tools email",
"expires_at": 1698765432,
"registration_client_uri": "https://auth.mcp.r167.dev/client/mcp_example.com_12345..."
}
Client Expiration: Clients expire after 60 days of inactivity. Expiration is refreshed whenever refresh tokens are used.
MCP Scope Format
Scopes must follow the pattern: mcp:<domain>:<server>
where:
domain
: Must match the redirect URI domain and client registration domainserver
: Must exist insrc/config.json
configuration- User must be in the server's
allowed_users
list
Example: mcp:example.com:github-tools email
API Endpoints
GET /authorize
- OAuth authorization endpointPOST /token
- Token exchange endpointGET /.well-known/jwks.json
- Public keys for token validationGET /.well-known/oauth-authorization-server
- OAuth metadataGET /auth/github/callback
- GitHub OAuth callbackPOST /validate
- Validate JWT access tokensPOST /admin/revoke
- Revoke access or refresh tokensPOST /register
- Register new OAuth client (dynamic registration)GET /client/{client_id}
- Get client informationGET /health
- Health check
Token Validation
Option 1: Server-side Validation (Recommended)
Resource servers validate access tokens by:
- Fetching public keys from
/.well-known/jwks.json
- Verifying JWT signature with RS256
- Validating claims (issuer, audience, expiration)
- Checking audience matches expected MCP scope
Example validation (pseudo-code):
const token = request.headers.authorization.replace('Bearer ', '');
const publicKey = await fetchPublicKey();
const payload = await verifyJWT(token, publicKey);
if (payload.aud === 'mcp:example.com:github-tools') {
// Grant access to user payload.sub (GitHub user ID)
}
Option 2: Using the Validation Endpoint
For debugging or simple validation, use the /validate
endpoint:
# With Authorization header
curl -X POST https://auth.mcp.r167.dev/validate \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# With request body
curl -X POST https://auth.mcp.r167.dev/validate \
-H "Content-Type: application/json" \
-d '{"token": "YOUR_ACCESS_TOKEN"}'
Response:
{
"valid": true,
"payload": {
"token_type": "access",
"sub": "12345678",
"aud": "mcp:example.com:github-tools",
"iss": "https://auth.mcp.r167.dev",
"exp": 1698765432,
"iat": 1698761832,
"email": "user@example.com"
}
}
Note: The system uses D1 database for state storage, not KV storage.
Security Features
- PKCE: All authorization flows require PKCE for security
- Encrypted Refresh Tokens: AES-GCM encryption with key rotation
- Scope Binding: Tokens bound to specific MCP scopes
- Domain Validation: MCP scope domain must match redirect URI
- User Authorization: ACL-based access control per MCP server
- Token Rotation: Refresh tokens are rotated on use
- Secure Headers: Proper CORS and security headers
Configuration
D1 Database
The server automatically creates required tables on first startup:
authorization_codes
- Temporary authorization codes (10 min TTL)refresh_tokens
- Refresh token metadata (30 day TTL)user_sessions
- User authentication sessions (30 min TTL)client_approvals
- Stored consent decisions (30 day TTL)revoked_tokens
- Revoked refresh tokens (expires with token)registered_clients
- Dynamic client registrations (60 day inactivity expiration)
Key Rotation
Refresh token encryption supports key rotation:
# Generate new encryption key
NEW_KEY=$(openssl rand -base64 32)
wrangler secret put REFRESH_ENCRYPTION_KEY --text "$NEW_KEY"
Old tokens remain valid during transition period.
Monitoring
- Health check endpoint:
GET /health
- Cloudflare Workers analytics and logs
- Error logging for debugging
Advanced Deployment
For detailed deployment procedures, advanced configuration, and troubleshooting, see .
Contributing
- Fork the repository
- Create a feature branch
- Run tests:
pnpm test
- Submit a pull request
License
MIT License - see LICENSE file for details.