ThunderPhone 2.0 正式上线。全程自助,低至2美分/分钟。查看发布公告

Connect tools & data

通过 OAuth 连接

授权 MCP 客户端和 ThunderPhone CLI,无需共享 API 密钥。

OAuth 允许应用在您批准的权限范围内连接到一个 ThunderPhone 组织。目录客户端默认应使用 OAuth。对于需要手动配置 Bearer 令牌的客户端,组织 API 密钥仍然可用。

批准连接

在您的 MCP 客户端中发起连接。登录 ThunderPhone,检查应用名称和请求的权限,选择一个组织,然后选择 批准。如果并非由您发起连接或您不信任该应用,请选择 拒绝。应用名称由其开发者提供,并非验证标识。

读取权限会公开指定的数据;请求 calls:read 时,其中包括录音和转录文本。写入权限可以更改或删除资源;通话、活动、电话号码购买和部署可能产生费用或影响生产环境。您的组织角色仍然适用。

对于 CLI 连接,请打开终端中显示的验证链接,比对八字符代码,选择您的组织,然后批准。仅打开链接不会授予访问权限。代码将在 15 分钟后过期。

断开应用连接

在控制台中打开 组织 → API 密钥 → 已授权应用,然后选择 撤销。这会撤销您为当前组织选择的授权,包括其访问令牌和刷新令牌。如果您想再次授权该应用,请从应用中重新连接。

MCP 客户端发现

使用服务器 URL https://api.thunderphone.com/v1/mcp。未携带有效身份验证的请求会收到 401,并附带:

WWW-Authenticate: Bearer resource_metadata="https://api.thunderphone.com/.well-known/oauth-protected-resource"

获取该文档,然后获取位于 https://api.thunderphone.com/.well-known/oauth-authorization-server 的授权服务器元数据。资源元数据也可通过 /.well-known/oauth-protected-resource/v1/mcp 获取。请使用返回的端点,而非自行构造端点。资源标识符为 https://api.thunderphone.com/v1/mcp。

服务器支持采用 S256 PKCE 的授权码流程、轮换刷新令牌、公共动态客户端注册、撤销和设备授权授予。没有客户端密钥或隐式授予。OpenID 发现也可通过 /.well-known/openid-configuration 获取;其中包含相同的授权服务器字段,以及 subject_types_supported: ["public"] 和用户信息端点。不支持 ID 令牌和客户端 ID 元数据文档(CIMD)。

注册公共客户端

将 JSON 发送至 POST /v1/oauth/register:

{
  "client_name": "My MCP client",
  "redirect_uris": ["http://127.0.0.1:8765/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"]
}

保存返回的 client_id。重定向必须使用 HTTPS,或在 127.0.0.1 或 localhost 上使用 HTTP。注册精确的回调 URI,包括端口和路径。不接受片段和嵌入式凭据。可选的 client_uri 和 logo_uri 必须使用 HTTPS;ThunderPhone 不会在注册期间获取它们。注册受到速率限制。已注册的客户端不会过期,并且在连接被撤销后仍保持注册状态。HTTPS 回调包括 https://chatgpt.com/connector/oauth/<id> 和 https://chatgpt.com/connector_platform_oauth_redirect。每个连接均可注册自己的客户端。

授权码

使用 client_id、精确注册的 redirect_uri、response_type=code、随机 state、scope、code_challenge、code_challenge_method=S256 以及 resource=https://api.thunderphone.com/v1/mcp 打开已发现的授权端点。将质询计算为新生成的高熵 PKCE 验证器的未填充 base64url SHA-256 摘要。在交换授权码前,检查返回的 state 和 iss。每个授权响应,包括拒绝和协议错误,都会通过 iss 标识签发者,并且必须与发现到的 issuer 完全匹配。无效客户端或回调的错误会在本地返回,而不会重定向至该回调。

使用表单编码在 POST /v1/oauth/token 交换(也接受 JSON):

grant_type=authorization_code
client_id=<your client id>
code=<single-use authorization code>
redirect_uri=<exact registered redirect URI>
code_verifier=<original PKCE verifier>
resource=https://api.thunderphone.com/v1/mcp

可选的 resource 参数可同时用于授权和令牌请求(包括刷新和设备交换)。省略时,默认使用发现到的 MCP 资源。存在时,它必须与该资源完全匹配;其他值会返回 invalid_target。访问令牌携带该受众,MCP 会拒绝缺少该受众或具有不同受众的令牌,并返回 401 和发现质询。

授权请求和授权码会在 10 分钟后过期。每个令牌响应均包含 access_token、token_type(Bearer)、expires_in(默认 3600 秒)、refresh_token、scope、organization_id 和 organization_name。仅通过 Authorization: Bearer 标头发送访问令牌。切勿将令牌放入 URL、日志、源代码控制或聊天中。

刷新和撤销

在令牌端点使用 grant_type=refresh_token、client_id、refresh_token 和 resource 刷新令牌。以原子方式保存新的刷新令牌,并停止使用旧令牌。刷新令牌在 30 天内未成功刷新后过期。可选的 scope 可缩小已授予的权限。始终包含 offline_access,并且始终会签发刷新令牌。未包含 scope 的初始请求仅授予 offline_access,因此客户端应请求所需的权限。

重复使用授权码和已轮换的刷新令牌会撤销整个授权。在一个客户端内串行执行刷新操作;重放已成功交换的凭据不是安全的重试策略。

如需断开连接,将 token 和 client_id 发送至 POST /v1/oauth/revoke。撤销任一令牌都会撤销其授权,包括由其签发的所有令牌。未知令牌会返回成功,而不会泄露其是否存在。控制台会话可通过 GET /v1/oauth/grants 列出自身授权,并可通过 DELETE /v1/oauth/grants/<id> 撤销其中一项,其中 X-ThunderPhone-Org 用于选择组织。

设备授权

设备授权仅限预注册客户端;动态注册的客户端会收到 unauthorized_client。预注册的公共客户端 thunderphone-cli 支持设备授权和刷新。将 client_id=thunderphone-cli 和 scope 发送至 POST /v1/oauth/device/code。向用户显示 user_code 和 verification_uri,或者打开 verification_uri_complete。

使用 grant_type=urn:ietf:params:oauth:grant-type:device_code、client_id 和 device_code 轮询令牌端点,并至少等待返回的 interval(5 秒)。收到 authorization_pending 时继续。在 slow_down 时,对每个后续请求使用响应中返回的新 interval(增加 5 秒)。在 access_denied、expired_token 或任何其他错误时停止。切勿自动批准设备代码。

预注册的 thunderphone-mcp 客户端在任意端口上接受 http://127.0.0.1/callback 和 http://localhost/callback。方案、主机、路径和查询必须匹配;令牌交换必须使用授权中精确的重定向 URI(包括端口)。动态注册的客户端要求精确匹配重定向 URI,包括端口。如需其他路径,请动态注册不同的回调。

账户身份和工作区域名检查

请求 openid email 以及客户端所需操作范围。使用 Bearer 标头中的访问令牌调用发现到的 userinfo_endpoint(GET /v1/oauth/userinfo)。成功响应包含:

{
  "sub": "123",
  "email": "person@example.com",
  "email_verified": true,
  "name": "Example User",
  "org_id": 456
}

sub 是稳定的用户标识符;org_id 是在同意期间选择的组织。该端点要求同时具备两个身份范围,任一缺失时返回 403。如果账户没有已验证的电子邮件资料,则会返回带有 error=access_denied 的 403,而不会断言未经验证的电子邮件可信。无效、过期、已撤销或受众错误的令牌会返回 401。人工会话令牌和组织 API 密钥无法调用用户信息端点。不会签发 ID 令牌。

可用权限

类别作用域
智能体和智能体导入agents:read, agents:write
通话calls:read, calls:write
电话号码、已拦截来电者和 VoIPnumbers:read, numbers:write
知识库knowledge:read, knowledge:write
营销活动campaigns:read, campaigns:write
集成、Webhook 端点、MCP 服务器integrations:read, integrations:write
语音voices:read
测试场景、测试运行、验证testing:read, testing:write
计费billing:read
账户身份和已验证邮箱openid, email(userinfo 两者均必需)
持久连接offline_access(始终包含)

GET、HEAD 和 OPTIONS 使用读取范围;其他方法使用写入范围。无法通过 OAuth 修改语音和账单;POST /v1/voices/preview 使用 voices:read,因为它会预览语音而不更改其配置。MCP 工具会强制执行其底层 REST 操作的范围。即使授权用户同时属于两个组织,跨组织转移也会被拒绝。其他 API 类别,包括 API 密钥管理和人工账户设置,无法通过 OAuth 使用。REST 操作缺少权限时,会返回 403,并附带 WWW-Authenticate: Bearer error="insufficient_scope", scope="..."。无效或过期的访问令牌会返回 401。

MCP 工具身份验证信号

tools/list 中的每个工具都包含 securitySchemes: [{"type": "oauth2", "scopes": ["agents:read"]}],其中的范围对应该工具的 REST 操作。公开文档工具使用空范围列表,但仍需要经过身份验证的连接。

有效令牌缺少工具所需范围时,会收到 HTTP 200,其中 JSON-RPC result 包含 isError: true、content 中的说明文本以及 _meta["mcp/www_authenticate"]。后者是一个数组,包含带有 resource_metadata、error="insufficient_scope"、error_description 和所需 scope 的 Bearer 质询。该工具不会执行。使用此质询请求扩展授权同意。缺少或无效的身份验证仍会返回 HTTP 401 和 WWW-Authenticate;REST 范围失败仍会返回 HTTP 403。

凭证保留

API 会在预发布环境和生产环境中每小时运行一次 python manage.py oauth_cleanup。它会移除过期的授权请求和设备代码。仅当其授权被撤销或整个令牌族失效后,才会清理过期的访问令牌、授权码和刷新令牌哈希。只要令牌族仍有可用的刷新令牌、授权码、已批准的设备代码或访问令牌,已使用的哈希就会被保留,因此清理操作不会禁用重放检测。