Initial commit
This commit is contained in:
403
references/authentication.md
Normal file
403
references/authentication.md
Normal file
@@ -0,0 +1,403 @@
|
||||
# MCP Authentication Patterns - Comparison Matrix
|
||||
|
||||
This document compares all 4 authentication patterns supported by Cloudflare MCP servers.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Table
|
||||
|
||||
| Pattern | Security | Complexity | Use Case | Client Setup |
|
||||
|---------|----------|------------|----------|--------------|
|
||||
| **No Auth** | ⚠️ None | ⭐ Simple | Internal tools, dev | Just URL |
|
||||
| **Token Validation** | ✅ Good | ⭐⭐ Medium | Custom auth, API keys | Bearer token |
|
||||
| **OAuth Proxy** | ✅✅ Excellent | ⭐⭐⭐ Medium | GitHub, Google, Azure | OAuth flow |
|
||||
| **Full OAuth Provider** | ✅✅✅ Maximum | ⭐⭐⭐⭐⭐ Complex | Custom identity | Full OAuth 2.1 |
|
||||
|
||||
---
|
||||
|
||||
## Pattern 1: No Authentication
|
||||
|
||||
### When to Use
|
||||
- Internal tools (private network only)
|
||||
- Development and testing
|
||||
- Public APIs (intentionally open)
|
||||
|
||||
### Security
|
||||
⚠️ **WARNING**: Anyone with the URL can access your MCP server
|
||||
|
||||
### Implementation
|
||||
```typescript
|
||||
export class MyMCP extends McpAgent<Env> {
|
||||
// No authentication required
|
||||
}
|
||||
|
||||
export default {
|
||||
fetch(request, env, ctx) {
|
||||
return MyMCP.serveSSE("/sse").fetch(request, env, ctx);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Client Configuration
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"my-mcp": {
|
||||
"url": "https://my-mcp.workers.dev/sse"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pros
|
||||
✅ Simplest to implement
|
||||
✅ No OAuth flow complexity
|
||||
✅ Fast to test
|
||||
|
||||
### Cons
|
||||
❌ No security
|
||||
❌ Anyone can use your server
|
||||
❌ Can't identify users
|
||||
|
||||
---
|
||||
|
||||
## Pattern 2: Token Validation (JWT)
|
||||
|
||||
### When to Use
|
||||
- Pre-authenticated clients
|
||||
- Custom authentication systems
|
||||
- API key-based access
|
||||
- Service-to-service communication
|
||||
|
||||
### Security
|
||||
✅ **GOOD**: Secure if tokens properly managed
|
||||
|
||||
### Implementation
|
||||
```typescript
|
||||
import { JWTVerifier } from "agents/mcp";
|
||||
|
||||
const verifier = new JWTVerifier({
|
||||
secret: env.JWT_SECRET,
|
||||
issuer: "your-auth-server",
|
||||
audience: "your-mcp-server"
|
||||
});
|
||||
|
||||
export default {
|
||||
async fetch(request, env, ctx) {
|
||||
// Verify token before serving MCP requests
|
||||
const token = request.headers.get("Authorization")?.replace("Bearer ", "");
|
||||
|
||||
if (!token) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = await verifier.verify(token);
|
||||
// Token valid, serve MCP
|
||||
return MyMCP.serveSSE("/sse").fetch(request, env, ctx);
|
||||
} catch (error) {
|
||||
return new Response("Invalid token", { status: 403 });
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Client Configuration
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"my-mcp": {
|
||||
"url": "https://my-mcp.workers.dev/sse",
|
||||
"headers": {
|
||||
"Authorization": "Bearer YOUR_JWT_TOKEN_HERE"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pros
|
||||
✅ Simple integration with existing auth
|
||||
✅ No OAuth flow needed
|
||||
✅ Works with any JWT issuer
|
||||
|
||||
### Cons
|
||||
❌ Token management (refresh, expiry)
|
||||
❌ Manual token distribution
|
||||
❌ Client must handle token lifecycle
|
||||
|
||||
---
|
||||
|
||||
## Pattern 3: OAuth Proxy (workers-oauth-provider)
|
||||
|
||||
### When to Use
|
||||
- Integrate with GitHub, Google, Azure, etc.
|
||||
- User-scoped tools (read/write GitHub repos)
|
||||
- Need user identity in tools
|
||||
- Production applications
|
||||
|
||||
### Security
|
||||
✅✅ **EXCELLENT**: Industry-standard OAuth 2.1
|
||||
|
||||
### Implementation
|
||||
```typescript
|
||||
import { OAuthProvider, GitHubHandler } from "@cloudflare/workers-oauth-provider";
|
||||
|
||||
export default new OAuthProvider({
|
||||
authorizeEndpoint: "/authorize",
|
||||
tokenEndpoint: "/token",
|
||||
clientRegistrationEndpoint: "/register",
|
||||
|
||||
defaultHandler: new GitHubHandler({
|
||||
clientId: (env) => env.GITHUB_CLIENT_ID,
|
||||
clientSecret: (env) => env.GITHUB_CLIENT_SECRET,
|
||||
scopes: ["repo", "user:email"],
|
||||
|
||||
context: async (accessToken) => {
|
||||
const octokit = new Octokit({ auth: accessToken });
|
||||
const { data: user } = await octokit.rest.users.getAuthenticated();
|
||||
|
||||
return {
|
||||
login: user.login,
|
||||
email: user.email,
|
||||
accessToken
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
kv: (env) => env.OAUTH_KV,
|
||||
|
||||
apiHandlers: {
|
||||
"/sse": MyMCP.serveSSE("/sse"),
|
||||
"/mcp": MyMCP.serve("/mcp")
|
||||
},
|
||||
|
||||
allowConsentScreen: true,
|
||||
allowDynamicClientRegistration: true
|
||||
});
|
||||
```
|
||||
|
||||
### Client Configuration
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"my-mcp": {
|
||||
"url": "https://my-mcp.workers.dev/sse",
|
||||
"auth": {
|
||||
"type": "oauth",
|
||||
"authorizationUrl": "https://my-mcp.workers.dev/authorize",
|
||||
"tokenUrl": "https://my-mcp.workers.dev/token"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Required Bindings
|
||||
```jsonc
|
||||
{
|
||||
"kv_namespaces": [
|
||||
{ "binding": "OAUTH_KV", "id": "YOUR_KV_ID" }
|
||||
],
|
||||
"vars": {
|
||||
"GITHUB_CLIENT_ID": "optional-preconfig",
|
||||
"GITHUB_CLIENT_SECRET": "optional-preconfig"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pros
|
||||
✅ Standard OAuth 2.1 flow
|
||||
✅ User identity in tools (`this.props.login`)
|
||||
✅ Automatic token management
|
||||
✅ Works with multiple providers
|
||||
✅ Dynamic Client Registration (no pre-config needed)
|
||||
✅ Consent screen for permissions
|
||||
|
||||
### Cons
|
||||
❌ Requires KV namespace
|
||||
❌ More complex than token validation
|
||||
❌ OAuth flow adds latency on first connect
|
||||
|
||||
---
|
||||
|
||||
## Pattern 4: Full OAuth Provider
|
||||
|
||||
### When to Use
|
||||
- You ARE the identity provider
|
||||
- Custom consent screens
|
||||
- Full control over auth flow
|
||||
- Enterprise B2B applications
|
||||
|
||||
### Security
|
||||
✅✅✅ **MAXIMUM**: Complete control over security
|
||||
|
||||
### Implementation
|
||||
Complex - requires full OAuth 2.1 server implementation.
|
||||
|
||||
See Cloudflare's `remote-mcp-authkit` template for example.
|
||||
|
||||
### Client Configuration
|
||||
Same as Pattern 3
|
||||
|
||||
### Pros
|
||||
✅ Full control over authentication
|
||||
✅ Custom user management
|
||||
✅ Custom consent screens
|
||||
✅ Fine-grained permissions
|
||||
✅ Works with any OAuth client
|
||||
|
||||
### Cons
|
||||
❌ Very complex to implement
|
||||
❌ Must handle OAuth 2.1 spec correctly
|
||||
❌ Token management, refresh, expiry
|
||||
❌ User database required
|
||||
❌ Audit logs recommended
|
||||
|
||||
---
|
||||
|
||||
## Supported OAuth Providers
|
||||
|
||||
### GitHub
|
||||
**Handler**: `GitHubHandler`
|
||||
**Scopes**: `repo`, `user:email`, `read:org`, `write:org`
|
||||
**Example**: `templates/mcp-oauth-proxy.ts`
|
||||
|
||||
### Google
|
||||
**Handler**: `GoogleHandler`
|
||||
**Scopes**: `openid`, `email`, `profile`, `https://www.googleapis.com/auth/drive.readonly`
|
||||
**Setup**: See `references/oauth-providers.md`
|
||||
|
||||
### Azure AD
|
||||
**Handler**: `AzureADHandler`
|
||||
**Scopes**: `openid`, `email`, `User.Read`
|
||||
**Setup**: See `references/oauth-providers.md`
|
||||
|
||||
### Custom Provider
|
||||
**Handler**: `GenericOAuthHandler`
|
||||
**Use case**: Any OAuth 2.1 compliant provider
|
||||
|
||||
---
|
||||
|
||||
## Migration Path
|
||||
|
||||
### From No Auth → Token Validation
|
||||
1. Generate JWT signing key
|
||||
2. Add JWTVerifier middleware
|
||||
3. Issue tokens to clients
|
||||
4. Update client config with Authorization header
|
||||
|
||||
### From Token Validation → OAuth Proxy
|
||||
1. Choose OAuth provider (GitHub, Google, etc.)
|
||||
2. Add KV namespace binding
|
||||
3. Replace fetch handler with OAuthProvider
|
||||
4. Update client config with OAuth URLs
|
||||
5. Remove Authorization headers
|
||||
|
||||
### From OAuth Proxy → Full OAuth Provider
|
||||
1. Implement OAuth 2.1 server logic
|
||||
2. Add user database (D1, KV, external)
|
||||
3. Implement consent screen UI
|
||||
4. Implement token refresh logic
|
||||
5. Add audit logging
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### All Patterns
|
||||
✅ Use HTTPS in production (automatic on Cloudflare)
|
||||
✅ Validate all inputs (Zod schemas)
|
||||
✅ Log authentication attempts
|
||||
✅ Rate limit authentication endpoints
|
||||
|
||||
### Token Validation
|
||||
✅ Use strong secrets (256-bit minimum)
|
||||
✅ Short token expiry (15-60 minutes)
|
||||
✅ Implement token refresh
|
||||
✅ Rotate secrets regularly
|
||||
|
||||
### OAuth Patterns
|
||||
✅ Always use `allowConsentScreen: true` in production
|
||||
✅ Request minimal scopes needed
|
||||
✅ Validate redirect URIs
|
||||
✅ Use PKCE for authorization code flow
|
||||
✅ Store tokens securely (KV, encrypted)
|
||||
|
||||
### Full OAuth Provider
|
||||
✅ Implement OAuth 2.1 spec correctly
|
||||
✅ Use authorization code flow (not implicit)
|
||||
✅ Validate all OAuth parameters
|
||||
✅ Implement token introspection
|
||||
✅ Add audit logging for all auth events
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### ❌ Disabling Consent Screen
|
||||
```typescript
|
||||
allowConsentScreen: false // ❌ NEVER in production
|
||||
```
|
||||
|
||||
Users won't see what permissions they're granting!
|
||||
|
||||
### ❌ Storing Secrets in Code
|
||||
```typescript
|
||||
const secret = "my-secret-key"; // ❌ NEVER commit secrets
|
||||
```
|
||||
|
||||
Use environment variables or secrets management.
|
||||
|
||||
### ❌ Overly Broad Scopes
|
||||
```typescript
|
||||
scopes: ["repo", "delete_repo", "admin:org"] // ❌ Too powerful
|
||||
```
|
||||
|
||||
Request minimal scopes needed.
|
||||
|
||||
### ❌ No Token Validation
|
||||
```typescript
|
||||
// ❌ Trusting token without verification
|
||||
const token = request.headers.get("Authorization");
|
||||
// Use token without verifying...
|
||||
```
|
||||
|
||||
Always validate tokens before use.
|
||||
|
||||
---
|
||||
|
||||
## Testing Authentication
|
||||
|
||||
### Test No Auth
|
||||
```bash
|
||||
curl https://my-mcp.workers.dev/sse
|
||||
# Should connect immediately
|
||||
```
|
||||
|
||||
### Test Token Validation
|
||||
```bash
|
||||
# Without token (should fail)
|
||||
curl https://my-mcp.workers.dev/sse
|
||||
|
||||
# With token (should succeed)
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
https://my-mcp.workers.dev/sse
|
||||
```
|
||||
|
||||
### Test OAuth Flow
|
||||
```bash
|
||||
# Use MCP Inspector
|
||||
npx @modelcontextprotocol/inspector@latest
|
||||
|
||||
# Or use Claude Desktop (will trigger OAuth flow)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Further Reading
|
||||
|
||||
- **OAuth 2.1 Spec**: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1
|
||||
- **workers-oauth-provider**: https://github.com/cloudflare/workers-oauth-provider
|
||||
- **Cloudflare Auth Docs**: https://developers.cloudflare.com/agents/model-context-protocol/authorization/
|
||||
- **MCP Auth Spec**: https://spec.modelcontextprotocol.io/specification/draft/basic/authorization/
|
||||
Reference in New Issue
Block a user