---
title: "MCP クライアントの OAuth"
description: "ユーザーを TwexAPI にサインインさせる MCP クライアントを作るためのリファレンス：ディスカバリー、動的クライアント登録、PKCE、スコープ、トークン、更新、取り消し。"
---

TwexAPI は MCP サーバー用に OAuth 2.1 の認可サーバーを運用しています。Claude、ChatGPT、Cursor などの MCP クライアントは自動的にこれを使います。独自のクライアントを作る場合や、クライアントの問題を調べる場合はこのページを参照してください。

- PKCE 付きの認可コードフロー（`S256` のみ）。
- パブリッククライアントのみで、クライアントシークレットはありません。動的クライアント登録（RFC 7591）で登録します。
- ユーザーは `https://twexapi.io/oauth/consent` で TwexAPI アカウントにサインインし、承認します。
- トークンは不透明な文字列で、`https://api.twexapi.io/mcp` でのみ使えます。TwexAPI の API キーではないため、REST API は呼び出せません。
- 呼び出しはユーザーの API キーを通じてそのクレジットから課金されるため、承認にはクレジットの残った有効なキーが必要です。

スクリプトやバックエンドから TwexAPI を呼ぶだけなら、[API キー](/authentication) を使ってください。

## ディスカバリー

認証情報なしで `https://api.twexapi.io/mcp` にリクエストすると、次のヘッダー付きで `401` が返ります：

```http
WWW-Authenticate: Bearer realm="twexapi", resource_metadata="https://api.twexapi.io/.well-known/oauth-protected-resource/mcp", scope="mcp:read mcp:write"
```

### 保護リソースのメタデータ

`GET https://api.twexapi.io/.well-known/oauth-protected-resource/mcp`（`/.well-known/oauth-protected-resource` でも同じ内容）：

```json
{
  "resource": "https://api.twexapi.io/mcp",
  "authorization_servers": ["https://api.twexapi.io"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["mcp:read", "mcp:write"],
  "resource_name": "TwexAPI"
}
```

### 認可サーバーのメタデータ

`GET https://api.twexapi.io/.well-known/oauth-authorization-server`：

```json
{
  "issuer": "https://api.twexapi.io",
  "authorization_endpoint": "https://api.twexapi.io/oauth/authorize",
  "token_endpoint": "https://api.twexapi.io/oauth/token",
  "registration_endpoint": "https://api.twexapi.io/oauth/register",
  "revocation_endpoint": "https://api.twexapi.io/oauth/revoke",
  "response_types_supported": ["code"],
  "response_modes_supported": ["query"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["none"],
  "revocation_endpoint_auth_methods_supported": ["none"],
  "scopes_supported": ["mcp:read", "mcp:write"],
  "authorization_response_iss_parameter_supported": true
}
```

<a id="scopes"></a>

## スコープ

| スコープ | 許可される内容 |
| --- | --- |
| `mcp:read` | `explore` と `twexapi_request`（読み取り専用のエンドポイント）。常に許可されます。 |
| `mcp:write` | `twexapi_write`（ツイートとリプライの投稿）。ユーザーは同意ページで拒否できます。 |

両方を求めるには `mcp:read mcp:write` を指定します。不明なスコープは無視され、認識できるスコープが 1 つもない場合は両方を求めたものとして扱われます。ユーザーが実際に許可した内容は、トークンレスポンスの `scope` フィールドで確認できます。

## 1. クライアントを登録する

```http
POST https://api.twexapi.io/oauth/register
Content-Type: application/json

{
  "client_name": "My Agent",
  "redirect_uris": ["http://127.0.0.1:53682/callback"]
}
```

```json
{
  "client_id": "twx_client_...",
  "client_id_issued_at": 1792600000,
  "client_name": "My Agent",
  "redirect_uris": ["http://127.0.0.1:53682/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}
```

| フィールド | ルール |
| --- | --- |
| `redirect_uris` | 必須。1〜10 個の URI で、それぞれ次のいずれか：`https://`、`localhost`・`127.0.0.1`・`[::1]` 上の `http://`、または `cursor://` のようなプライベートスキーム。フラグメントやユーザー情報は使えません。 |
| `client_name` | 任意。最大 100 文字。同意ページとユーザーの **Authorized apps**（認可済みアプリ）一覧に表示されます。 |
| `token_endpoint_auth_method` | 任意。`none` のみ受け付けます。 |
| `grant_types` | 任意。`authorization_code` と `refresh_token` の部分集合。 |
| `response_types` | 任意。`code` のみ。 |

登録は IP アドレスごとに 1 時間あたり 30 クライアントまでです。クライアント登録は 180 日間有効で、ユーザーがそのクライアントで認可を始めるたびに延長されます。登録は一度だけ行い、`client_id` を使い回してください。

## 2. PKCE のペアを作る

Node.js：

```js
import crypto from "node:crypto";

const verifier = crypto.randomBytes(32).toString("base64url");
const challenge = crypto.createHash("sha256").update(verifier).digest("base64url");
```

Python：

```python
import base64, hashlib, secrets

verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).rstrip(b"=").decode()
challenge = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode()).digest()).rstrip(b"=").decode()
```

verifier は `A-Z a-z 0-9 - . _ ~` からなる 43〜128 文字にしてください。

## 3. ユーザーを認可に送る

ユーザーのブラウザで次の URL を開きます：

```txt
https://api.twexapi.io/oauth/authorize
  ?response_type=code
  &client_id=twx_client_...
  &redirect_uri=http%3A%2F%2F127.0.0.1%3A53682%2Fcallback
  &code_challenge=CHALLENGE
  &code_challenge_method=S256
  &state=RANDOM_STATE
  &scope=mcp%3Aread%20mcp%3Awrite
  &resource=https%3A%2F%2Fapi.twexapi.io%2Fmcp
```

| パラメーター | 必須 | 補足 |
| --- | --- | --- |
| `response_type` | はい | `code`。 |
| `client_id` | はい | 登録時に取得したもの。 |
| `redirect_uri` | はい | 登録済みの URI と完全に一致する必要があります。ループバックの `http` URI は任意のポートを使えます。 |
| `code_challenge`、`code_challenge_method` | はい | `S256` のみ。 |
| `state` | 推奨 | そのまま返されます。CSRF 対策として検証してください。 |
| `scope` | いいえ | [スコープ](#scopes) を参照。 |
| `resource` | いいえ | 指定する場合は `https://api.twexapi.io/mcp` にしてください。 |

TwexAPI はユーザーを `twexapi.io` の同意ページに送ります。ユーザーはサインインし、アプリ名と戻り先のホストを確認して、書き込みを許可するかを選び、承認または拒否します。リクエストは 10 分で期限切れになります。

## 4. コードを受け取る

承認されると、ブラウザはリダイレクト URI に戻ります：

```txt
http://127.0.0.1:53682/callback?code=CODE&state=RANDOM_STATE&iss=https%3A%2F%2Fapi.twexapi.io
```

`state` が一致すること、`iss` が `https://api.twexapi.io` であることを確認してください。拒否された場合は、`code` の代わりに `error=access_denied` が付きます。コードは 1 回限りで、2 分で期限切れになります。

`client_id` が不明な場合や `redirect_uri` が登録されていない場合、TwexAPI はリダイレクトせずに `400` エラーを表示します。そのため、設定を誤ったクライアントがユーザーを未確認のアドレスに送ることはありません。

## 5. コードをトークンに交換する

```http
POST https://api.twexapi.io/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=CODE
&redirect_uri=http%3A%2F%2F127.0.0.1%3A53682%2Fcallback
&client_id=twx_client_...
&code_verifier=VERIFIER
```

```json
{
  "access_token": "twx_at_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "twx_rt_...",
  "scope": "mcp:read mcp:write"
}
```

`redirect_uri` と `client_id` は認可リクエストと一致させてください。`resource=https://api.twexapi.io/mcp` を送ることもできます。JSON のボディも受け付けます。

## 6. MCP サーバーを呼び出す

```http
POST https://api.twexapi.io/mcp
Authorization: Bearer twx_at_...
Content-Type: application/json
Accept: application/json, text/event-stream
```

アクセストークンは `/mcp` でのみ使えます。期限切れ、取り消し済み、または不明なトークンには、`WWW-Authenticate` ヘッダーに `error="invalid_token"` を含む `401` が返ります。トークンを更新するか、ユーザーに再度サインインしてもらってください。

## トークンの更新

```http
POST https://api.twexapi.io/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=twx_rt_...
&client_id=twx_client_...
```

更新のたびに新しいアクセストークンと新しいリフレッシュトークンが返り、古いリフレッシュトークンは使えなくなります。毎回新しいペアを保存してください。古いリフレッシュトークンが再利用されると、TwexAPI は漏えいとみなして認可全体を取り消します。その認可のトークンはすべて使えなくなり、ユーザーは再度サインインする必要があります。

## 取り消し

```http
POST https://api.twexapi.io/oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=twx_rt_...
```

リフレッシュトークンを取り消すと認可全体が終了します。アクセストークンを取り消した場合は、そのトークンだけが無効になります。このエンドポイントは、不明なトークンに対しても常に `200` を返します。ユーザーは [ダッシュボード](https://twexapi.io/dashboard) の **Authorized apps**（認可済みアプリ）からもアプリを取り消すことができ、すぐに反映されます。

## トークンの有効期間

| 項目 | 有効期間 |
| --- | --- |
| 認可リクエスト（同意ページ） | 10 分 |
| 認可コード | 2 分、1 回限り |
| アクセストークン | 1 時間 |
| リフレッシュトークン | 30 日、使うたびにローテーション |
| 30 日間使われなかった認可 | 失効 |
| クライアント登録 | 180 日、認可のたびに延長 |

## エラー

エラーは標準的な OAuth の形式で返ります：

```json
{
  "error": "invalid_grant",
  "error_description": "The authorization code is invalid, expired or already used"
}
```

| エンドポイント | `error` | 原因 |
| --- | --- | --- |
| 登録 | `invalid_redirect_uri` | リダイレクト URI がない、形式が正しくない、または許可されていないスキームやホストを使っています。 |
| 登録 | `invalid_client_metadata` | サポートされていない `token_endpoint_auth_method`、`grant_types`、`response_types`。 |
| 登録 | `temporarily_unavailable`（`429`） | その IP アドレスからの登録が多すぎます。`client_id` を使い回してください。 |
| 認可 | `invalid_client`（`400`、リダイレクトなし） | `client_id` が不明です。先に登録してください。 |
| 認可 | `invalid_request`（`400`、リダイレクトなし） | `redirect_uri` がこのクライアントに登録されていません。 |
| 認可 | `unsupported_response_type` | `response_type` が `code` ではありません。 |
| 認可 | `invalid_request` | PKCE のパラメーターがない、または無効です。 |
| 認可 | `invalid_target` | `resource` が `https://api.twexapi.io/mcp` ではありません。 |
| 認可 | `access_denied` | ユーザーがアクセスを拒否しました。 |
| トークン | `invalid_grant` | コードまたはリフレッシュトークンが無効、期限切れ、使用済み、または別のクライアントに発行されたもの。PKCE の検証に失敗した、または認可が取り消されています。 |
| トークン | `invalid_target` | `resource` が一致しません。 |
| トークン | `unsupported_grant_type` | `authorization_code` か `refresh_token` を使ってください。 |

ユーザーのアカウントに有効な API キーやクレジットがない場合は、同意ページが承認の前に止めるため、呼び出しに使えないトークンがクライアントに渡ることはありません。
