AACWorkflow Docs

MCP OAuth 2.1 授权

为 MCP 客户端构建 OAuth 2.1 授权服务器,支持 PKCE、refresh 令牌轮换和基于范围的访问控制。

AACWorkflow 通过 MCP (Model Context Protocol) 使用 OAuth 2.1 授权暴露其 API。外部 MCP 客户端 — 包括 Claude、ChatGPT 连接器和自定义工具 — 通过 OAuth 服务器认证以获得绑定到 (user, workspace) 对的范围受限、可刷新的访问令牌。

概述

OAuth 服务器实现 Authorization Code grant 配合 PKCE (Proof Key for Code Exchange)、refresh 令牌轮换和动态客户端注册。这确保:

  • 用户控制 — 用户通过同意屏幕明确授予工作区访问权
  • 基于范围的访问 — 客户端声明需要的资源(issue、评论、智能体等)
  • 令牌生命周期 — 短期有效访问令牌(~15 分钟)和可刷新的长期令牌
  • 重放检测 — 重放刷新令牌会撤销整个令牌族,检测令牌泄漏

OAuth 流程

1. 客户端注册

客户端一次性通过以下方式注册:

POST /oauth/register
Content-Type: application/json

{
  "client_name": "My MCP Tool",
  "redirect_uris": ["http://localhost:5000/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "none"
}

返回 client_idclient_secret(公共客户端无密钥)。

2. 授权代码流程

客户端启动登录:

GET /oauth/authorize?
  client_id=<id>&
  redirect_uri=http://localhost:5000/callback&
  response_type=code&
  scope=issues:read+issues:write+comments:read&
  code_challenge=<sha256_hash>&
  code_challenge_method=S256

用户看到列出请求范围和要授予的工作区的同意屏幕。批准后,他们收到授权代码(有效期 10 分钟):

HTTP 302
Location: http://localhost:5000/callback?code=<auth_code>&state=<state>

3. 交换代码获取令牌

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=<auth_code>&
client_id=<id>&
code_verifier=<original_plain_challenge>&
redirect_uri=http://localhost:5000/callback

返回:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "<refresh_token>",
  "scope": "issues:read issues:write comments:read"
}

访问令牌是包含以下内容的有签名 JWT:

  • sub — 用户 ID
  • wsid — 工作区 ID
  • scope — 空格分隔的范围
  • exp — 过期时间(900 秒)

4. 刷新令牌轮换

当访问令牌过期时,使用刷新令牌:

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&
refresh_token=<refresh_token>&
client_id=<id>

返回新的访问令牌新的刷新令牌。旧刷新令牌自动失效。如果重放旧刷新令牌,服务器会撤销整个令牌族,表示可能的令牌泄漏。

范围

范围令牌定义客户端可以访问的资源:

范围访问权限
issues:read读取 issue、状态、时间线
issues:write创建、更新 issue;更改状态
comments:read读取 issue 评论和讨论线程
comments:write创建和编辑评论
agents:read列出智能体、查看详情
agents:write创建智能体、分配给 issue
runtimes:read查询运行时状态和日志
autopilot:run触发自动驾驶
dashboard:read查询使用情况和质量仪表板

客户端在授权期间请求范围子集。令牌仅以请求的范围颁发。如果刷新缩小范围,新令牌的范围少于原始令牌。

端点

方法路径目的
GET/.well-known/oauth-authorization-serverRFC 8414 元数据发现
GET/oauth/authorize同意 UI;颁发授权代码
POST/oauth/token代码-令牌和刷新流程
POST/oauth/register动态客户端注册 (RFC 7591)
POST/oauth/revokeRFC 7009 令牌撤销

发现

客户端可以发现授权服务器元数据:

GET /.well-known/oauth-authorization-server

返回:

{
  "issuer": "https://aacworkflow.example.com",
  "authorization_endpoint": "https://aacworkflow.example.com/oauth/authorize",
  "token_endpoint": "https://aacworkflow.example.com/oauth/token",
  "registration_endpoint": "https://aacworkflow.example.com/oauth/register",
  "revocation_endpoint": "https://aacworkflow.example.com/oauth/revoke",
  "scopes_supported": [
    "issues:read", "issues:write", "comments:read", "comments:write",
    "agents:read", "agents:write", "runtimes:read", "autopilot:run", "dashboard:read"
  ],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["none"],
  "code_challenge_methods_supported": ["S256"]
}

安全考虑

PKCE 强制code_challenge_method=S256 必需;不接受 plain

  • 准确的重定向 URI 匹配 — 重定向 URI 与注册值精确验证(无前缀匹配)
  • 授权代码一次性 — 授权代码只能交换一次;第二次尝试失败
  • Refresh 令牌轮换 — 每次刷新使先前的刷新令牌失效,检测和应对令牌泄漏
  • 短期有效访问令牌 — 访问令牌在 15 分钟后过期;客户端必须刷新以续期
  • 安全令牌存储 — 令牌在静态时哈希化(与个人访问令牌相同的 KDF);明文令牌不保存

撤销访问

随时撤销令牌(访问或刷新):

POST /oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=<access_or_refresh_token>&
client_id=<id>

撤销刷新令牌会级联:从该刷新颁发的所有访问令牌也被失效。

与 MCP 的集成

外部 MCP 服务器使用 OAuth 令牌调用 AACWorkflow 工具。令牌在 Authorization 头中传递:

GET /api/issues
Authorization: Bearer <access_token>

服务器验证令牌签名、检查过期并强制范围。如果工具需要 issues:write 但令牌仅有 issues:read,调用被拒绝并返回 403 Forbidden。

审计日志

每个 OAuth 事件(登录、令牌颁发、刷新、撤销、重放检测)记录在审计日志中以用于合规和调查。