---
title: "OAuth para clientes MCP"
description: "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](/authentication).

## Descubrimiento

Una solicitud sin credenciales a `https://api.twexapi.io/mcp` devuelve `401` con este header:

```http
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`):

```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"
}
```

### Metadatos del servidor de autorización

`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>

## 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

```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"
}
```

| 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:

```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()
```

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:

```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
```

| 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](#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:

```txt
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

```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` 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

```http
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

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

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

```http
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](https://twexapi.io/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:

```json
{
  "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.
