---
title: "OAuth pour les clients MCP"
description: "Référence pour créer un client MCP qui connecte les utilisateurs à TwexAPI : découverte, enregistrement dynamique des clients, PKCE, scopes, jetons, renouvellement et révocation."
---

TwexAPI exploite un serveur d'autorisation OAuth 2.1 pour son serveur MCP. Les clients MCP comme Claude, ChatGPT et Cursor l'utilisent automatiquement. Consultez cette page lorsque vous créez votre propre client ou en déboguez un.

- Flux code d'autorisation avec PKCE (`S256` uniquement).
- Clients publics uniquement, sans client secret. Enregistrez-les via l'enregistrement dynamique des clients (RFC 7591).
- Les utilisateurs se connectent avec leur compte TwexAPI et approuvent l'accès sur `https://twexapi.io/oauth/consent`.
- Les jetons sont des chaînes opaques qui ne fonctionnent que sur `https://api.twexapi.io/mcp`. Ce ne sont pas des clés API TwexAPI et ils ne permettent pas d'appeler l'API REST.
- Les appels sont facturés sur les crédits de l'utilisateur via sa clé API : l'approbation exige donc une clé active avec des crédits.

Si vous voulez seulement appeler TwexAPI depuis un script ou un backend, utilisez une [clé API](/authentication).

## Découverte

Une requête sans identifiants vers `https://api.twexapi.io/mcp` renvoie `401` avec cet en-tête :

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

### Métadonnées de la ressource protégée

`GET https://api.twexapi.io/.well-known/oauth-protected-resource/mcp` (identique à `/.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"
}
```

### Métadonnées du serveur d'autorisation

`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 | Autorise |
| --- | --- |
| `mcp:read` | `explore` et `twexapi_request` (endpoints en lecture seule). Toujours accordé. |
| `mcp:write` | `twexapi_write` (publier des tweets et des réponses). L'utilisateur peut le refuser sur la page de consentement. |

Demandez `mcp:read mcp:write` pour obtenir les deux. Les scopes inconnus sont ignorés ; si aucun scope reconnu n'est présent, la demande est traitée comme si elle demandait les deux. Le champ `scope` de la réponse de jeton indique ce que l'utilisateur a réellement accordé.

## 1. Enregistrer un client

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

| Champ | Règles |
| --- | --- |
| `redirect_uris` | Obligatoire. De 1 à 10 URI, chacune parmi : `https://`, `http://` sur `localhost`, `127.0.0.1` ou `[::1]`, ou un schéma privé comme `cursor://`. Ni fragment ni informations utilisateur. |
| `client_name` | Facultatif, 100 caractères maximum. Affiché sur la page de consentement et dans la liste **Authorized apps** (applications autorisées) de l'utilisateur. |
| `token_endpoint_auth_method` | Facultatif. Seul `none` est accepté. |
| `grant_types` | Facultatif. Un sous-ensemble de `authorization_code` et `refresh_token`. |
| `response_types` | Facultatif. Seul `code` est accepté. |

L'enregistrement est limité à 30 clients par adresse IP et par heure. Un enregistrement de client dure 180 jours et est prolongé chaque fois qu'un utilisateur lance une autorisation avec lui. Enregistrez-vous une fois et réutilisez le `client_id`.

## 2. Créer une paire 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()
```

Le verifier doit comporter de 43 à 128 caractères parmi `A-Z a-z 0-9 - . _ ~`.

## 3. Envoyer l'utilisateur vers l'autorisation

Ouvrez cette URL dans le navigateur de l'utilisateur :

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

| Paramètre | Obligatoire | Remarques |
| --- | --- | --- |
| `response_type` | Oui | `code`. |
| `client_id` | Oui | Issu de l'enregistrement. |
| `redirect_uri` | Oui | Doit correspondre exactement à une URI enregistrée. Les URI `http` de loopback acceptent n'importe quel port. |
| `code_challenge`, `code_challenge_method` | Oui | `S256` uniquement. |
| `state` | Recommandé | Renvoyé tel quel. Vérifiez-le pour vous protéger contre le CSRF. |
| `scope` | Non | Voir [Scopes](#scopes). |
| `resource` | Non | S'il est envoyé, il doit valoir `https://api.twexapi.io/mcp`. |

TwexAPI envoie l'utilisateur vers la page de consentement sur `twexapi.io`. L'utilisateur se connecte, voit le nom de l'application et l'hôte vers lequel il sera renvoyé, choisit d'accorder ou non l'accès en écriture, puis approuve ou refuse. La demande expire au bout de 10 minutes.

## 4. Recevoir le code

Après approbation, le navigateur revient sur votre URI de redirection :

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

Vérifiez que `state` correspond et que `iss` vaut `https://api.twexapi.io`. En cas de refus, vous recevez `error=access_denied` au lieu de `code`. Le code est à usage unique et expire au bout de 2 minutes.

Si le `client_id` est inconnu ou si le `redirect_uri` n'est pas enregistré, TwexAPI affiche une erreur `400` au lieu de rediriger : un client mal configuré n'envoie donc jamais l'utilisateur vers une adresse non vérifiée.

## 5. Échanger le code contre des jetons

```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` et `client_id` doivent correspondre à la demande d'autorisation. Vous pouvez aussi envoyer `resource=https://api.twexapi.io/mcp`. Les corps JSON sont acceptés.

## 6. Appeler le serveur MCP

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

Les jetons d'accès ne fonctionnent que sur `/mcp`. Un jeton expiré, révoqué ou inconnu reçoit `401` avec `error="invalid_token"` dans l'en-tête `WWW-Authenticate`. Renouvelez le jeton ou demandez à l'utilisateur de se reconnecter.

## Renouveler les jetons

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

Chaque renouvellement renvoie un nouveau jeton d'accès et un nouveau refresh token, et l'ancien refresh token cesse de fonctionner. Enregistrez toujours la nouvelle paire. Si un ancien refresh token est réutilisé, TwexAPI le considère comme compromis et révoque l'autorisation entière : tous ses jetons cessent de fonctionner et l'utilisateur doit se reconnecter.

## Révocation

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

token=twx_rt_...
```

Révoquer un refresh token met fin à toute l'autorisation. Révoquer un jeton d'accès invalide uniquement ce jeton. L'endpoint renvoie toujours `200`, même pour des jetons inconnus. Les utilisateurs peuvent aussi révoquer une application sous **Authorized apps** (applications autorisées) dans le [tableau de bord](https://twexapi.io/dashboard), avec effet immédiat.

## Durée de vie des jetons

| Élément | Durée de vie |
| --- | --- |
| Demande d'autorisation (page de consentement) | 10 minutes |
| Code d'autorisation | 2 minutes, usage unique |
| Jeton d'accès | 1 heure |
| Refresh token | 30 jours, renouvelé à chaque utilisation |
| Autorisation inutilisée pendant 30 jours | Expire |
| Enregistrement de client | 180 jours, prolongé à chaque autorisation |

## Erreurs

Les erreurs suivent le format OAuth standard :

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

| Endpoint | `error` | Cause |
| --- | --- | --- |
| Enregistrement | `invalid_redirect_uri` | URI de redirection absente ou mal formée, ou utilisant un schéma ou un hôte non autorisé. |
| Enregistrement | `invalid_client_metadata` | `token_endpoint_auth_method`, `grant_types` ou `response_types` non pris en charge. |
| Enregistrement | `temporarily_unavailable` (`429`) | Trop d'enregistrements depuis votre adresse IP. Réutilisez votre `client_id`. |
| Autorisation | `invalid_client` (`400`, sans redirection) | `client_id` inconnu. Enregistrez-vous d'abord. |
| Autorisation | `invalid_request` (`400`, sans redirection) | Le `redirect_uri` n'est pas enregistré pour ce client. |
| Autorisation | `unsupported_response_type` | `response_type` ne vaut pas `code`. |
| Autorisation | `invalid_request` | Paramètres PKCE absents ou invalides. |
| Autorisation | `invalid_target` | `resource` ne vaut pas `https://api.twexapi.io/mcp`. |
| Autorisation | `access_denied` | L'utilisateur a refusé l'accès. |
| Jeton | `invalid_grant` | Code ou refresh token invalide, expiré, déjà utilisé ou émis pour un autre client ; ou échec de la vérification PKCE ; ou autorisation révoquée. |
| Jeton | `invalid_target` | `resource` ne correspond pas. |
| Jeton | `unsupported_grant_type` | Utilisez `authorization_code` ou `refresh_token`. |

Si le compte de l'utilisateur n'a pas de clé API active ni de crédits, la page de consentement le bloque avant l'approbation : votre client ne reçoit donc jamais un jeton incapable d'effectuer des appels.
