MCP クライアントの OAuth
ユーザーを 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 キー を使ってください。
ディスカバリー
認証情報なしで https://api.twexapi.io/mcp にリクエストすると、次のヘッダー付きで 401 が返ります:
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 でも同じ内容):
{
"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:
{
"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
}
スコープ
| スコープ | 許可される内容 |
|---|---|
mcp:read |
explore と twexapi_request(読み取り専用のエンドポイント)。常に許可されます。 |
mcp:write |
twexapi_write(ツイートとリプライの投稿)。ユーザーは同意ページで拒否できます。 |
両方を求めるには mcp:read mcp:write を指定します。不明なスコープは無視され、認識できるスコープが 1 つもない場合は両方を求めたものとして扱われます。ユーザーが実際に許可した内容は、トークンレスポンスの scope フィールドで確認できます。
1. クライアントを登録する
POST https://api.twexapi.io/oauth/register
Content-Type: application/json
{
"client_name": "My Agent",
"redirect_uris": ["http://127.0.0.1:53682/callback"]
}
{
"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:
import crypto from "node:crypto";
const verifier = crypto.randomBytes(32).toString("base64url");
const challenge = crypto.createHash("sha256").update(verifier).digest("base64url");
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 を開きます:
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 |
いいえ | スコープ を参照。 |
resource |
いいえ | 指定する場合は https://api.twexapi.io/mcp にしてください。 |
TwexAPI はユーザーを twexapi.io の同意ページに送ります。ユーザーはサインインし、アプリ名と戻り先のホストを確認して、書き込みを許可するかを選び、承認または拒否します。リクエストは 10 分で期限切れになります。
4. コードを受け取る
承認されると、ブラウザはリダイレクト URI に戻ります:
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. コードをトークンに交換する
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
{
"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 サーバーを呼び出す
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 が返ります。トークンを更新するか、ユーザーに再度サインインしてもらってください。
トークンの更新
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 は漏えいとみなして認可全体を取り消します。その認可のトークンはすべて使えなくなり、ユーザーは再度サインインする必要があります。
取り消し
POST https://api.twexapi.io/oauth/revoke
Content-Type: application/x-www-form-urlencoded
token=twx_rt_...
リフレッシュトークンを取り消すと認可全体が終了します。アクセストークンを取り消した場合は、そのトークンだけが無効になります。このエンドポイントは、不明なトークンに対しても常に 200 を返します。ユーザーは ダッシュボード の Authorized apps(認可済みアプリ)からもアプリを取り消すことができ、すぐに反映されます。
トークンの有効期間
| 項目 | 有効期間 |
|---|---|
| 認可リクエスト(同意ページ) | 10 分 |
| 認可コード | 2 分、1 回限り |
| アクセストークン | 1 時間 |
| リフレッシュトークン | 30 日、使うたびにローテーション |
| 30 日間使われなかった認可 | 失効 |
| クライアント登録 | 180 日、認可のたびに延長 |
エラー
エラーは標準的な OAuth の形式で返ります:
{
"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 キーやクレジットがない場合は、同意ページが承認の前に止めるため、呼び出しに使えないトークンがクライアントに渡ることはありません。