Aller au contenu principal

Tokens Éphémères et Sécurité

Mis à jour le 29 juillet 2026

Le problème de la clé API côté client

Une application vocale qui tourne dans un navigateur ou sur un mobile ne peut pas embarquer votre clé API. N’importe quel visiteur ouvre les outils de développement, lit la clé dans le bundle JavaScript ou dans un en-tête de requête, et l’utilise ensuite à votre compte jusqu’à épuisement de votre quota. Aucune obfuscation ne protège une valeur que le client doit forcément posséder pour appeler l’API.

La réponse de xAI tient dans les tokens éphémères, ou client secrets : un jeton à durée de vie courte, généré par votre serveur, qui autorise une session vocale et rien d’autre.

600s
durée par défaut
3600s
durée maximum
POST
/v1/realtime/client_secrets
1 usage
par token

Le mécanisme

Le principe se résume à cinq mouvements :

  1. Votre backend (serveur sécurisé) appelle POST /v1/realtime/client_secrets avec votre clé API
  2. L’API retourne un token temporaire avec une durée de vie limitée
  3. Votre backend envoie ce token au client (navigateur/mobile)
  4. Le client utilise ce token pour se connecter au WebSocket Voice Agent
  5. Le token expire après utilisation ou après sa durée de vie

Ce qui fuit désormais du côté client n’a plus grande valeur : un jeton à usage unique, périmé en quelques minutes, inutilisable pour autre chose qu’une session déjà consommée. Côté serveur, la génération s’écrit en quelques lignes. Notez que l’appel commence par vérifier l’utilisateur : sans ce contrôle, votre backend n’est qu’un distributeur public de jetons.

// Backend Node.js (Express)
app.post("/api/voice-token", async (req, res) => {
  // Verifier l'authentification de l'utilisateur
  if (!req.user) return res.status(401).json({ error: "Non autorise" });

  const response = await fetch(
    "https://api.x.ai/v1/realtime/client_secrets",
    {
      method: "POST",
      headers: {
        "Authorization": "Bearer " + process.env.XAI_API_KEY,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        ttl: 600  // 10 minutes
      })
    }
  );

  const data = await response.json();
  res.json({ token: data.client_secret });
});

Le client, lui, ne connaît que votre propre route : il demande un jeton, puis ouvre le WebSocket avec.

// Frontend (navigateur)
async function startVoiceSession() {
  // Demander un token au backend
  const tokenRes = await fetch("/api/voice-token", { method: "POST" });
  const { token } = await tokenRes.json();

  // Se connecter au Voice Agent avec le token ephemere
  const ws = new WebSocket("wss://api.x.ai/v1/realtime", {
    headers: { "Authorization": "Bearer " + token }
  });

  // ... configuration de la session
}

L’architecture de bout en bout

Assemblé, le flux complet part de l’utilisateur qui s’authentifie sur votre application. Son client réclame ensuite un token vocal à votre backend, lequel contrôle l’authentification et les droits avant de générer le token éphémère via l’API xAI. Le jeton redescend vers le client, qui l’utilise pour ouvrir la session Voice Agent, et il expire automatiquement après usage ou à la fin de son TTL.

Cette vérification glissée entre la demande et la génération transforme un simple relais en point de contrôle, et c’est là que se logent vos règles métier. Vous pouvez plafonner le nombre de sessions vocales par utilisateur et par jour, pour qu’un compte unique ne consomme pas votre budget mensuel en une nuit. Vous pouvez réserver les jetons aux abonnements actifs, et faire ainsi respecter votre modèle commercial ailleurs que dans l’interface. Vous pouvez limiter la fréquence des demandes, pour qu’un client buggé ou malveillant ne réclame pas mille jetons à la minute. Vous pouvez enfin journaliser chaque génération : c’est votre seule base fiable pour le monitoring, la facturation interne et l’analyse d’un incident.

Les règles à ne pas transgresser

La clé API ne descend jamais côté client, sous aucune forme : ni dans le JavaScript front-end, ni dans une variable d’environnement exposée au build du navigateur — celles préfixées pour être injectées dans le bundle finissent publiques —, ni dans une URL, un log ou un message d’erreur affiché à l’utilisateur.

Réglez ensuite le TTL au plus juste. Une session vocale typique de cinq minutes vit très bien avec les 600 secondes par défaut ; le maximum de 3600 secondes ne se justifie que pour un usage qui l’exige réellement, car chaque minute supplémentaire est une minute pendant laquelle un jeton intercepté reste exploitable.

Quand une session s’étire au-delà du prévu, ne laissez pas le token mourir en pleine conversation : renouvelez-le avant l’échéance.

function scheduleTokenRenewal(ttl) {
  // Renouveler le token 60 secondes avant expiration
  setTimeout(async () => {
    const newToken = await requestNewToken();
    reconnectWithToken(newToken);
  }, (ttl - 60) * 1000);
}

Pour le TTS en mode HTTP, il existe une alternative encore plus simple aux jetons : le proxy. Le client envoie son texte à votre backend, votre backend appelle le TTS et lui retourne l’audio. La clé ne quitte jamais votre serveur, et vous gardez au passage un point naturel pour filtrer les contenus et compter la consommation.

Points clés à retenir

  • Les tokens éphémères sécurisent l’accès au Voice Agent depuis les applications côté client
  • Le endpoint POST /v1/realtime/client_secrets génère un token avec un TTL configurable (max 3600s)
  • Votre backend doit vérifier l’authentification et les droits avant de générer un token
  • N’exposez jamais votre clé API côté client, dans les URLs ou dans les logs
  • Pour le TTS HTTP, le proxying via votre backend est une alternative valide aux tokens éphémères