跳到内容
Twexapi
简体中文
Esc
↑↓导航↵打开⌘J预览
本页内容

MCP 客户端 OAuth

开发能让用户登录 TwexAPI 的 MCP 客户端时的参考:服务发现、动态客户端注册、PKCE、权限范围、token、续期与撤销。

TwexAPI 为其 MCP 服务器运行了一个 OAuth 2.1 授权服务器。Claude、ChatGPT、Cursor 等 MCP 客户端会自动使用它。如果你在开发自己的客户端,或者需要排查客户端问题,请阅读本页。

  • 授权码流程加 PKCE(只支持 S256)。
  • 只支持公开客户端,没有 client secret。通过动态客户端注册(RFC 7591)注册。
  • 用户在 https://twexapi.io/oauth/consent 用自己的 TwexAPI 账号登录并确认授权。
  • token 是不透明字符串,只能用于 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 即可同时申请两者。无法识别的权限范围会被忽略;如果请求中没有任何可识别的权限范围,则视为同时申请两者。token 响应中的 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 地址每小时最多注册 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 必须是 43 到 128 个字符,只能包含 A-Z a-z 0-9 - . _ ~。

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. 接收授权码

用户同意后,浏览器会回到你的回调地址:

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。用户拒绝时,回调中会带 error=access_denied 而不是 code。授权码只能使用一次,2 分钟后过期。

如果 client_id 不存在,或 redirect_uri 没有注册过,TwexAPI 会直接显示 400 错误而不是跳转,这样配置错误的客户端永远不会把用户带到未经验证的地址。

5. 用授权码换取 token

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

访问 token 只能用于 /mcp。token 过期、被撤销或无法识别时,会返回 401,WWW-Authenticate 头中带 error="invalid_token";此时请用 refresh token 续期,或让用户重新登录。

续期 token

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_...

每次续期都会返回新的访问 token 和新的 refresh token,旧的 refresh token 随即失效。请每次都保存新的一对。如果旧的 refresh token 被再次使用,TwexAPI 会认为它已泄露并撤销整个授权,该授权下的所有 token 都会失效,用户需要重新登录。

撤销

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

token=twx_rt_...

撤销 refresh token 会结束整个授权;撤销访问 token 只会让该 token 失效。无论 token 是否存在,这个端点都返回 200。用户也可以在 控制台 的 Authorized apps(已授权应用)中撤销任意应用,立即生效。

有效期

项目 有效期
授权请求(授权页) 10 分钟
授权码 2 分钟,只能使用一次
访问 token 1 小时
Refresh token 30 天,每次使用都会轮换
连续 30 天未使用的授权 失效
客户端注册 180 天,每次授权都会延长

错误

错误采用标准的 OAuth 格式:

{
  "error": "invalid_grant",
  "error_description": "The authorization code is invalid, expired or already used"
}
端点 error 原因
注册 invalid_redirect_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 用户拒绝了授权。
Token invalid_grant 授权码或 refresh token 无效、已过期、已使用或属于其他客户端;PKCE 校验失败;或授权已被撤销。
Token invalid_target resource 不匹配。
Token unsupported_grant_type 请使用 authorization_code 或 refresh_token。

如果用户的账号没有可用的 API 密钥或没有额度,授权页会在用户点击同意之前就拦下,所以你的客户端不会拿到无法调用的 token。

这个页面有帮助吗?