---
title: "OAuth で接続"
description: "API キーを共有せずに、MCP クライアントと ThunderPhone CLI を認可します。"
---

OAuth を使用すると、承認した権限でアプリを 1 つの ThunderPhone 組織に接続できます。ディレクトリクライアントでは、デフォルトで OAuth を使用してください。手動で設定する Bearer トークンが必要なクライアント向けには、組織 API キーも引き続き利用できます。

## 接続を承認する

MCP クライアントで接続を開始します。ThunderPhone にログインし、アプリ名と要求された権限を確認して、組織を選択し、**承認**を選択します。接続を開始していない場合やアプリを信頼できない場合は、**拒否**を選択します。アプリ名は開発者によって提供されるものであり、認証バッジではありません。

読み取り権限では、`calls:read` が要求された場合の録音や文字起こしを含め、指定されたデータにアクセスできます。書き込み権限ではリソースを変更または削除できます。通話、キャンペーン、電話番号の購入、デプロイは、費用の発生や本番環境への影響を伴う可能性があります。組織でのロールも引き続き適用されます。

CLI 接続では、ターミナルに表示される認証リンクを開き、8 文字のコードを照合して、組織を選択し、承認します。リンクを開くだけではアクセスは付与されません。コードは 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 トークンおよびクライアント ID メタデータドキュメント（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 は登録時にこれらを取得しません。登録にはレート制限があります。登録済みクライアントは期限切れにならず、接続が失効しても登録されたままです。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` を確認してください。拒否およびプロトコルエラーを含むすべての認可レスポンスは、検出された `issuer` と完全に一致する `iss` で発行者を識別します。無効なクライアントまたはコールバックに対するエラーは、そのコールバックにリダイレクトせずローカルで返されます。

フォームエンコーディングを使用して `POST /v1/oauth/token` で交換します（JSON も受け付けます）。

```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 の一致が必要です。別のパスが必要な場合は、異なるコールバックを動的に登録してください。

### アカウント ID とワークスペースドメインの確認

クライアントに必要な操作スコープとともに、`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` は同意中に選択された組織です。このエンドポイントには両方の ID スコープが必要で、いずれかが欠けている場合は `403` を返します。アカウントに確認済みメールプロファイルがない場合は、未確認メールが信頼されていると主張するのではなく、`error=access_denied` を含む `403` を返します。無効、期限切れ、失効済み、またはオーディエンスが異なるトークンは `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` |
| アカウント ID と確認済みメールアドレス | `openid`, `email`（userinfo には両方必須） |
| 永続的な接続 | `offline_access`（常に含まれる） |

GET、HEAD、OPTIONSは読み取りスコープを使用し、その他のメソッドは書き込みスコープを使用します。音声および請求の変更操作はOAuthでは利用できません。`POST /v1/voices/preview` は設定を変更せずに音声をプレビューするため、`voices:read` を使用します。MCPツールは、基盤となるREST操作のスコープを適用します。認可するユーザーが両方の組織に所属している場合でも、組織間の移行は拒否されます。APIキー管理や人間のアカウント設定を含むその他のAPIファミリーは、OAuthでは利用できません。REST操作で権限が不足している場合は、`WWW-Authenticate: Bearer error="insufficient_scope", scope="..."` とともに `403` が返されます。無効または期限切れのアクセストークンでは `401` が返されます。


### MCPツールの認証シグナル

`tools/list` 内のすべてのツールには、そのツールのREST操作のスコープを含む `securitySchemes: [{"type": "oauth2", "scopes": ["agents:read"]}]` が含まれます。公開ドキュメント用ツールは空のスコープリストを使用しますが、認証済み接続が必要です。

有効なトークンにツールに必要なスコープがない場合、HTTP `200` と、`isError: true`、`content` 内の説明テキスト、および `_meta["mcp/www_authenticate"]` を含むJSON-RPC `result` が返されます。後者は、`resource_metadata`、`error="insufficient_scope"`、`error_description`、および必要な `scope` を含むBearerチャレンジを格納した配列です。ツールは実行されません。このチャレンジを使用して、拡張された同意をリクエストしてください。認証がない場合または無効な場合は、引き続き `WWW-Authenticate` とともにHTTP `401` が返されます。RESTスコープの失敗では、引き続きHTTP `403` が返されます。

## 認証情報の保持

APIは、ステージング環境と本番環境で毎時 `python manage.py oauth_cleanup` を実行します。期限切れの認可リクエストとデバイスコードを削除します。期限切れのアクセストークン、認可コード、リフレッシュトークンハッシュは、そのグラントが失効するか、ファミリー全体が無効になった後にのみ削除されます。使用済みハッシュは、ファミリーに使用可能なリフレッシュトークン、認可コード、承認済みデバイスコード、またはアクセストークンが存在する間保持されるため、クリーンアップによってリプレイ検出が無効になることはありません。
