OAuth授权服务器

一个基于Cloudflare Workers构建的生产级OAuth 2.1/OIDC授权服务器,用于保护Model Context Protocol (MCP)资源,支持通过GitHub进行两步认证。

  • by R167
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 R167/mcp-oauth

使用说明

MCP OAuth授权服务器

基于Cloudflare Workers构建的生产就绪OAuth 2.1/OIDC授权服务器,用于保护模型上下文协议(MCP)资源。该服务器通过GitHub实现2跳身份验证,具有全面的安全功能。

特性

  • 符合OAuth 2.1标准:使用PKCE的授权码流
  • GitHub集成:通过GitHub OAuth进行2跳身份验证
  • MCP范围验证:MCP服务器的细粒度访问控制
  • 安全:JWT令牌、加密刷新令牌、PKCE强制
  • Cloudflare员工:使用D1数据库存储的无服务器部署
  • 标准符合性:OAuth 2.1、OIDC发现、JWKS

建筑

看 架构.md 获取详细的架构文档。

快速开始

发展

# Install dependencies
pnpm install

# Start development server
pnpm run dev

服务器在上运行 http://localhost:8787 具有自动生成的测试密钥。

临时部署(即用型!)

该项目包括一个预配置的暂存环境:

# 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

暂存URL: https://mcp-oauth-authorization-server-staging.wmdurand.workers.dev

备注:必须配置机密,服务器才能正常工作。

生产部署

# 1. Set up production secrets
./scripts/setup-secrets.sh prod

# 2. Deploy to production
pnpm run deploy:prod

生产URL: https://auth.mcp.r167.dev

配置

GitHub OAuth应用程序设置

使用以下设置创建GitHub OAuth应用程序:

  • 临时回拨: https://mcp-oauth-authorization-server-staging.wmdurand.workers.dev/auth/github/callback
  • 生产回访: https://auth.mcp.r167.dev/auth/github/callback

MCP服务器

在中配置MCP服务器 src/config.json (生产)或 src/config.staging.json (分期):

{
  "servers": {
    "your-domain.com": {
      "your-server": {
        "name": "Your MCP Server",
        "description": "Description of what this server provides",
        "allowed_users": ["github-username1", "github-username2"]
      }
    }
  }
}

所需配置

Cloudflare的秘密

变量 描述
GITHUB_CLIENT_ID GitHub OAuth应用程序客户端ID
GITHUB_CLIENT_SECRET GitHub OAuth应用程序客户端密钥
JWT_PRIVATE_KEY 用于JWT签名的RS256私钥
JWT_PUBLIC_KEY 用于JWT验证的RS256公钥
REFRESH_ENCRYPTION_KEY 用于刷新令牌加密的AES-256密钥

环境变量

变量 描述 设置
WORKER_BASE_URL 已部署工作程序的完整URL wrangler.jsonc

发展

# Start development server
pnpm run dev

# Run tests
pnpm test

# Type checking
pnpm run type-check

# Format code
pnpm run format

自动密码设置

使用提供的脚本轻松配置所有必需的密钥:

# For staging environment
./scripts/setup-secrets.sh staging

# For production environment  
./scripts/setup-secrets.sh prod

脚本将:

  • 提示输入GitHub OAuth凭据
  • 自动生成JWT密钥对(或接受手动输入)
  • 自动生成刷新令牌加密密钥(或接受手动输入)
  • 自动配置所有机密

用法

OAuth流

  1. 授权请求:客户端将用户重定向到 /authorize 带PKCE参数
  2. GitHub身份验证:用户通过GitHub进行身份验证
  3. 范围验证:服务器验证MCP范围和用户权限
  4. 同意屏幕:用户批准访问(如果之前已批准,则跳过)
  5. 授权码:服务器向客户端返回授权码
  6. 代币交换:客户端使用PKCE验证器交换访问/刷新令牌的代码

客户注册

所有OAuth客户端在使用前必须通过动态客户端注册端点进行注册:

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"
  }'

答复:

{
  "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..."
}

客户端过期:客户端在60天不活动后过期。每当使用刷新令牌时,过期都会刷新。

MCP范围格式

范围必须遵循以下模式: mcp:<domain>:<server> 哪里:

  • domain:必须与重定向URI域和客户端注册域匹配
  • server:必须存在于 src/config.json 配置
  • 用户必须在服务器的 allowed_users 列表

例子: mcp:example.com:github-tools email

API终点

  • GET /authorize -OAuth授权端点
  • POST /token -令牌交换端点
  • GET /.well-known/jwks.json -用于令牌验证的公钥
  • GET /.well-known/oauth-authorization-server -OAuth元数据
  • GET /auth/github/callback -GitHub OAuth回调
  • POST /validate -验证JWT访问令牌
  • POST /admin/revoke -撤销访问或刷新令牌
  • POST /register -注册新的OAuth客户端(动态注册)
  • GET /client/{client_id} -获取客户信息
  • GET /health -健康检查

令牌验证

选项1:服务器端验证(推荐)

资源服务器通过以下方式验证访问令牌:

  1. 从获取公钥 /.well-known/jwks.json
  2. 用RS256验证JWT签名
  3. 验证索赔(签发人、受众、到期)
  4. 检查受众是否与预期的MCP范围匹配

验证示例(伪代码):

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)
}

选项2:使用验证端点

对于调试或简单验证,请使用 /validate 端点:

# 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"}'

答复:

{
  "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"
  }
}

备注:系统使用D1数据库进行状态存储,而不是KV存储。

安全功能

  • PKCE:所有授权流都需要PKCE来保证安全
  • 加密刷新令牌:带密钥轮换的AES-GCM加密
  • 范围绑定:绑定到特定MCP作用域的令牌
  • 域验证:MCP作用域必须与重定向URI匹配
  • 用户授权:每个MCP服务器基于ACL的访问控制
  • 代币轮换:刷新令牌在使用时轮换
  • 安全标头:正确的CORS和安全标头

配置

D1数据库

服务器在首次启动时自动创建所需的表:

  • authorization_codes -临时授权码(10分钟TTL)
  • refresh_tokens -刷新令牌元数据(30天TTL)
  • user_sessions -用户身份验证会话(30分钟TTL)
  • client_approvals -存储的同意决定(30天TTL)
  • revoked_tokens -已撤销的刷新令牌(随令牌过期)
  • registered_clients -动态客户端注册(60天不活动过期)

关键点旋转

刷新令牌加密支持密钥轮换:

# Generate new encryption key
NEW_KEY=$(openssl rand -base64 32)
wrangler secret put REFRESH_ENCRYPTION_KEY --text "$NEW_KEY"

旧代币在过渡期内仍然有效。

监控

  • 健康检查端点: GET /health
  • Cloudflare Workers分析和日志
  • 调试错误记录

高级部署

有关详细的部署过程、高级配置和故障排除,请参阅 部署.md.

贡献

  1. 分叉存储库
  2. 创建要素分支
  3. 运行测试: pnpm test
  4. 提交拉取请求

许可证

MIT许可证-有关详细信息,请参阅许可证文件。