OAuth para clientes MCP
Referencia para crear un cliente MCP que inicie sesión de usuarios en TwexAPI: descubrimiento, registro dinámico de clientes, PKCE, scopes, tokens, renovación y revocación.
TwexAPI opera un servidor de autorización OAuth 2.1 para su servidor MCP. Los clientes MCP como Claude, ChatGPT y Cursor lo usan automáticamente. Consulta esta página cuando crees tu propio cliente o depures uno.
- Flujo de código de autorización con PKCE (solo
S256). - Solo clientes públicos, sin client secret. Regístralos con el registro dinámico de clientes (RFC 7591).
- Los usuarios inician sesión con su cuenta de TwexAPI y aprueban el acceso en
https://twexapi.io/oauth/consent. - Los tokens son cadenas opacas que solo funcionan en
https://api.twexapi.io/mcp. No son API keys de TwexAPI y no sirven para llamar a la API REST. - Las llamadas se cobran a los créditos del usuario mediante su API key, así que aprobar requiere una key activa con créditos.
Si solo quieres llamar a TwexAPI desde un script o un backend, usa una API key.
Descubrimiento
Una solicitud sin credenciales a https://api.twexapi.io/mcp devuelve 401 con este header:
WWW-Authenticate: Bearer realm="twexapi", resource_metadata="https://api.twexapi.io/.well-known/oauth-protected-resource/mcp", scope="mcp:read mcp:write"
Metadatos del recurso protegido
GET https://api.twexapi.io/.well-known/oauth-protected-resource/mcp (lo mismo en /.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"
}
Metadatos del servidor de autorización
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
}
Scopes
| Scope | Permite |
|---|---|
mcp:read |
explore y twexapi_request (endpoints de solo lectura). Siempre se concede. |
mcp:write |
twexapi_write (publicar tweets y respuestas). El usuario puede rechazarlo en la página de consentimiento. |
Solicita mcp:read mcp:write para pedir ambos. Los scopes desconocidos se ignoran; si no hay ningún scope reconocido, la solicitud se trata como si pidiera ambos. El campo scope de la respuesta del token indica lo que el usuario concedió realmente.
1. Registra un cliente
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"
}
| Campo | Reglas |
|---|---|
redirect_uris |
Obligatorio. De 1 a 10 URIs, cada una de uno de estos tipos: https://, http:// en localhost, 127.0.0.1 o [::1], o un esquema privado como cursor://. No se permiten fragmentos ni información de usuario. |
client_name |
Opcional, hasta 100 caracteres. Se muestra en la página de consentimiento y en la lista Authorized apps (apps autorizadas) del usuario. |
token_endpoint_auth_method |
Opcional. Solo se acepta none. |
grant_types |
Opcional. Un subconjunto de authorization_code y refresh_token. |
response_types |
Opcional. Solo se acepta code. |
El registro está limitado a 30 clientes por dirección IP por hora. Un registro de cliente dura 180 días y se extiende cada vez que un usuario inicia una autorización con él. Registra una vez y reutiliza el client_id.
2. Crea un par 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()
El verifier debe tener entre 43 y 128 caracteres de A-Z a-z 0-9 - . _ ~.
3. Envía al usuario a autorizar
Abre esta URL en el navegador del usuario:
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
| Parámetro | Obligatorio | Notas |
|---|---|---|
response_type |
Sí | code. |
client_id |
Sí | Del registro. |
redirect_uri |
Sí | Debe coincidir exactamente con una URI registrada. Las URIs http de loopback aceptan cualquier puerto. |
code_challenge, code_challenge_method |
Sí | Solo S256. |
state |
Recomendado | Se devuelve sin cambios. Verifícalo para protegerte de CSRF. |
scope |
No | Consulta Scopes. |
resource |
No | Si lo envías, debe ser https://api.twexapi.io/mcp. |
TwexAPI envía al usuario a la página de consentimiento en twexapi.io. El usuario inicia sesión, ve el nombre de la app y el host al que volverá, elige si concede acceso de escritura y aprueba o rechaza. La solicitud expira a los 10 minutos.
4. Recibe el código
Al aprobar, el navegador vuelve a tu URI de redirección:
http://127.0.0.1:53682/callback?code=CODE&state=RANDOM_STATE&iss=https%3A%2F%2Fapi.twexapi.io
Comprueba que state coincida y que iss sea https://api.twexapi.io. Si el usuario rechaza, recibes error=access_denied en lugar de code. El código es de un solo uso y expira a los 2 minutos.
Si el client_id es desconocido o el redirect_uri no está registrado, TwexAPI muestra un error 400 en lugar de redirigir, así que un cliente mal configurado nunca envía al usuario a una dirección no verificada.
5. Canjea el código por tokens
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 y client_id deben coincidir con la solicitud de autorización. También puedes enviar resource=https://api.twexapi.io/mcp. Se aceptan cuerpos JSON.
6. Llama al servidor MCP
POST https://api.twexapi.io/mcp
Authorization: Bearer twx_at_...
Content-Type: application/json
Accept: application/json, text/event-stream
Los access tokens solo funcionan en /mcp. Un token expirado, revocado o desconocido recibe 401 con error="invalid_token" en el header WWW-Authenticate. Renueva el token o pide al usuario que vuelva a iniciar sesión.
Renueva los tokens
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_...
Cada renovación devuelve un nuevo access token y un nuevo refresh token, y el refresh token anterior deja de funcionar. Guarda siempre el par nuevo. Si un refresh token anterior se vuelve a usar, TwexAPI lo trata como filtrado y revoca toda la autorización: todos sus tokens dejan de funcionar y el usuario debe volver a iniciar sesión.
Revocación
POST https://api.twexapi.io/oauth/revoke
Content-Type: application/x-www-form-urlencoded
token=twx_rt_...
Revocar un refresh token termina toda la autorización. Revocar un access token invalida solo ese token. El endpoint siempre devuelve 200, incluso para tokens desconocidos. Los usuarios también pueden revocar una app en Authorized apps (apps autorizadas) del dashboard, con efecto inmediato.
Vigencia de los tokens
| Elemento | Vigencia |
|---|---|
| Solicitud de autorización (página de consentimiento) | 10 minutos |
| Código de autorización | 2 minutos, un solo uso |
| Access token | 1 hora |
| Refresh token | 30 días, rotado en cada uso |
| Autorización sin usar durante 30 días | Expira |
| Registro de cliente | 180 días, extendido en cada autorización |
Errores
Los errores usan el formato estándar de OAuth:
{
"error": "invalid_grant",
"error_description": "The authorization code is invalid, expired or already used"
}
| Endpoint | error |
Causa |
|---|---|---|
| Registro | invalid_redirect_uri |
URI de redirección ausente o mal formada, o con un esquema o host no permitido. |
| Registro | invalid_client_metadata |
token_endpoint_auth_method, grant_types o response_types no admitidos. |
| Registro | temporarily_unavailable (429) |
Demasiados registros desde tu dirección IP. Reutiliza tu client_id. |
| Autorización | invalid_client (400, sin redirección) |
client_id desconocido. Regístrate primero. |
| Autorización | invalid_request (400, sin redirección) |
El redirect_uri no está registrado para este cliente. |
| Autorización | unsupported_response_type |
response_type no es code. |
| Autorización | invalid_request |
Parámetros PKCE ausentes o inválidos. |
| Autorización | invalid_target |
resource no es https://api.twexapi.io/mcp. |
| Autorización | access_denied |
El usuario rechazó el acceso. |
| Token | invalid_grant |
Código o refresh token inválido, expirado, ya usado o emitido para otro cliente; o falló la verificación PKCE; o se revocó la autorización. |
| Token | invalid_target |
resource no coincide. |
| Token | unsupported_grant_type |
Usa authorization_code o refresh_token. |
Si la cuenta del usuario no tiene una API key activa o créditos, la página de consentimiento lo bloquea antes de aprobar, así que tu cliente nunca recibe un token que no pueda hacer llamadas.