---
title: "使用 OAuth 連接"
description: "授權 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`，內容如下：

```http
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"]` 和 userinfo 端點。不支援 ID 權杖及 Client ID Metadata Documents（CIMD）。

### 註冊公開用戶端

將 JSON 傳送至 `POST /v1/oauth/register`：

```json
{
  "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 不會在註冊期間擷取這些 URI。註冊設有速率限制。已註冊的用戶端不會過期，並會在連線被撤銷後維持註冊狀態。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 驗證器計算為 SHA-256 摘要，再以不含填充字元的 base64url 編碼，所得結果即為 challenge。在交換授權碼前，檢查回傳的 `state` 及 `iss`。每個授權回應，包括拒絕及通訊協定錯誤，均會以 `iss` 識別發行者，並與已探索的 `issuer` 完全一致。無效用戶端或回調的錯誤會在本機回傳，不會重新導向至該回調。

使用表單編碼（亦接受 JSON）在 `POST /v1/oauth/token` 交換：

```text
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`）。成功回應包含：

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

`sub` 是穩定的使用者識別碼；`org_id` 是在同意授權期間所選的機構。此端點要求兩項身分範圍，如缺少任何一項便會回傳 `403`。如帳戶沒有已驗證的電郵設定檔，會以 `403` 及 `error=access_denied` 回應，而不會斷言未驗證電郵值得信任。無效、過期、已撤銷或受眾錯誤的權杖會回傳 `401`。真人登入工作階段權杖及機構 API 金鑰不能呼叫 userinfo。不會發出 ID 權杖。

## 可用權限

| 類別 | 範圍 |
| --- | --- |
| 智能體及智能體匯入 | `agents:read`, `agents:write` |
| 通話 | `calls:read`, `calls:write` |
| 電話號碼及 VoIP | `numbers: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` 及包含 `isError: true` 的 JSON-RPC `result`，並在 `content` 提供說明文字，以及提供 `_meta["mcp/www_authenticate"]`。後者為一個陣列，包含帶有 `resource_metadata`、`error="insufficient_scope"`、`error_description` 及所需 `scope` 的 Bearer 質詢。工具不會執行。使用此質詢要求擴大授權同意。缺少或無效的驗證仍會傳回附帶 `WWW-Authenticate` 的 HTTP `401`；REST 範圍失敗則仍會傳回 HTTP `403`。

## 憑證保留

API 會在預備環境及正式環境每小時執行一次 `python manage.py oauth_cleanup`。它會移除過期的授權請求及裝置代碼。過期的存取權杖、授權代碼及重新整理權杖雜湊，只有在其授權已被撤銷或整個憑證家族已失效後才會清除。只要憑證家族仍有可用的重新整理權杖、授權代碼、已批准的裝置代碼或存取權杖，已使用的雜湊便會保留，確保清理程序不會停用重播偵測。
