OAuth受众验证演示

一个演示如何在MCP服务器中正确实施OAuth受众验证的最小化可复现示例,遵循RFC 8707标准。

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

使用说明

安全MCP演示-OAuth受众验证

一个最小的可重复示例,演示了根据RFC 8707在MCP(模型上下文协议)服务器中进行正确的OAuth受众验证。

问题

一些MCP客户端无法发送 resource 或 audience 请求OAuth令牌时的参数,违反了RFC 8707和MCP规范,破坏了受众限制访问令牌。

应该发生什么(符合RFC 8707)

  1. MCP服务器通告: "resource": "https://example.com/google-drive-mcp"
  2. 客户端在授权请求中包含资源: resource=https://example.com/google-drive-mcp
  3. 客户端在令牌请求中包含资源: resource=https://example.com/google-drive-mcp
  4. 令牌的发放与匹配 aud 声称
  5. 令牌验证成功✅

发生了什么(风帆虫)

  1. MCP服务器通告: "resource": "https://example.com/google-drive-mcp"
  2. 客户端 省略资源 在授权请求中❌
  3. 客户端 忽略资源和受众 在令牌请求中❌
  4. 令牌由通用受众(仅限来源)发行
  5. 令牌验证失败,因为 aud 声明与MCP服务器的资源URI不匹配

为什么这很重要

每 RFC 9728第7.4节,受众限制访问令牌可防止为一个资源服务器颁发的令牌在另一个服务器上使用。如果没有适当的受众验证,一个MCP服务器的令牌可能会在同一主机上的不同MCP服务器上重复使用。

真实世界测试结果

此演示已在多个MCP客户端上进行了测试。以下是实际结果:

✅ 游标-符合RFC 8707标准

[OAuth Server] Authorization request received:
  Resource: http://localhost:3000/google-drive-mcp  ✅

[OAuth Server] Token request received:
  Requested Resource: http://localhost:3000/google-drive-mcp  ✅

[MCP Server] Token validation:
  Expected audience: http://localhost:3000/google-drive-mcp
  Actual audience: http://localhost:3000/google-drive-mcp
  ✅ VALIDATION SUCCESSFUL

结果:游标成功连接并可以使用所有MCP功能。

❌ Windsurf-违反RFC 8707

[OAuth Server] Authorization request received:
  Resource: undefined  ❌ NOT SENT

[OAuth Server] Token request received:
  Requested Audience: NOT PROVIDED  ❌
  Requested Resource: NOT PROVIDED  ❌

[MCP Server] Token validation:
  Expected audience: http://localhost:3000/google-drive-mcp
  Actual audience: http://localhost:3000
  ❌ VALIDATION FAILED: Audience mismatch!

结果:Windsurf无法连接。令牌验证失败,因为没有发送资源参数。

规格违规(Windsurf)

  1. 授权请求中缺少资源 -违反MCP规范第2.5.1节
  2. 令牌请求中缺少资源/受众 -违反RFC 8707第2节
  3. 发现端点错误 请求: /.well-known/oauth-protected-resource 而不是 /.well-known/oauth-protected-resource/google-drive-mcp

安装

npm install

用法

启动演示服务器

npm install
npm run dev

这将启动一个包含以下内容的组合服务器:

  • 模拟OAuth授权服务器 -向请求的受众发放JWT令牌
  • 模拟MCP服务器 -使用OAuth验证实现MCP JSON-RPC协议

使用自动脚本进行快速测试

./test.sh

此脚本演示:

  • ✅ 具有正确受众的令牌(http://localhost:3000/google-drive-mcp) → 请求成功
  • ❌ 已剥离路径的令牌(http://localhost:3000) → 请求失败,受众不匹配

使用真实MCP客户端进行测试

该服务器实现了一个合适的MCP服务器,可以用真实的MCP客户端(Claude Code、Cursor、Windsurf等)进行测试。

将此配置添加到MCP客户端设置中:

{
  "mcpServers": {
    "secure-mcp-demo": {
      "url": "http://localhost:3000/google-drive-mcp",
      "transport": "http"
    }
  }
}

当MCP客户端连接时,它将:

  1. 尝试在没有令牌的情况下调用MCP服务器
  2. 收到401回复 WWW-Authenticate 包含资源URI的标头
  3. 从以下位置发现OAuth元数据 .well-known/oauth-protected-resource
  4. 使用以下命令从OAuth服务器请求令牌 audience 参数
  5. 使用令牌重试MCP请求

查看服务器日志 看看每个客户都在做什么。服务器记录每个请求,并提供有关OAuth参数的详细信息,从而可以轻松识别规范合规性问题。

相关规范

MCP规范

MCP授权-第2.5.1节:

MCP客户端必须实现RFC 8707中定义的OAuth 2.0的资源指示符…资源参数必须使用RFC 8707第2节中定义的MCP服务器的规范URI。

RFC 8707-OAuth 2.0的资源指示器

RFC 8707第2节:

“resource”参数的值必须是绝对URI。

规范要求使用 完整规范URI 作为资源标识符。

RFC 9728-OAuth 2.0安全最佳实践

RFC 9728第7.4节:

如果客户端希望与多个资源服务器交互,则应使用[RFC8707]请求受众受限访问令牌。

项目结构

secure-mcp/
├── src/
│   └── server.ts         # Combined OAuth + MCP server
├── package.json
├── tsconfig.json
└── README.md

运作原理

  1. MCP客户端发出初始请求 无需身份验证 /google-drive-mcp
  2. 服务器返回401 包括 WWW-Authenticate: Bearer resource="http://localhost:3000/google-drive-mcp"
  3. 客户端发现OAuth元数据 从 /.well-known/oauth-protected-resource/google-drive-mcp
  4. 客户端发现OAuth服务器 从 /.well-known/oauth-authorization-server
  5. 客户端动态注册 (可选,RFC 7591)通过 /register 端点
  6. 客户端发起授权 随着 resource 授权请求中的参数
  7. 客户端请求令牌 通过OAuth服务器 resource 或 audience 参数
    • ✅ 兼容客户端(游标):发送 resource=http://localhost:3000/google-drive-mcp
    • ❌ 不符合要求的客户端(Windsurf):两者均省略 resource 和 audience 参数
  8. OAuth服务器发出令牌 与要求的观众在 aud 声称
  9. 客户端重试MCP请求 随着 Authorization: Bearer <token>
  10. 服务器验证令牌 并检查是否 aud 声明与资源URI完全匹配
    • ✅ 如果匹配:请求成功
    • ❌ 如果不匹配:返回403,并显示详细的错误消息

已实现OAuth功能

  • ✅ 动态客户端注册(RFC 7591) -自动客户端注册
  • ✅ 资源指示器(RFC 8707) -受众限制令牌
  • ✅ PKCE(RFC 7636) -代码交换支持的证明密钥
  • ✅ 授权码流 -完整的OAuth 2.1流程
  • ✅ JWT访问令牌(RFC 9068) -结构化访问令牌 at+jwt 类型
  • ✅ OAuth发现(RFC 8414) - .well-known/oauth-authorization-server
  • ✅ 受保护资源元数据 - .well-known/oauth-protected-resource 根据MCP规范

许可证

阿帕奇-2.0

参考文献