Référence développeur

Émettre les tokens depuis votre backend

La méthode prise en charge pour émettre un token de connexion — et le champ qui, s'il disparaît, désactive silencieusement la session unique.

Retour aux produits développeurs

Pourquoi depuis le backend ?

Votre secret serveur ne part jamais dans l'app. Toute clé embarquée dans un APK peut être extraite et servir à usurper n'importe quel utilisateur.

Transmettez les infos de l'appareil

Votre serveur ne voit pas l'appareil. L'app les envoie à votre serveur, qui les relaie dans la même requête.

La panne est silencieuse

Sans device_id, la vérification « un compte, un appareil » sort tôt, sans erreur ni log. Le token réussit et la protection est éteinte.

Mesuré, pas supposé

Sur trois heures de connexions réelles : tokens émis côté backend, 3 224 connexions — 100 % sans identifiant d'appareil. Tokens émis par le kit, 1 641 connexions — 0 %.

Champs de la requête de token

POST sur /api/v1/token avec votre secret serveur dans l'en-tête.

ChampNiveauSignification
user_idstringRequisWho the token is for. Your own user id. (Previously `identity` — still accepted.)
room_idstringRequisWhich room they are joining. (Previously `room_name` — still accepted.)
device_idstringRecommandéA stable id for the PHYSICAL DEVICE — not the user, and not the session. This is what enforces one account on one device: when the same user_id joins from a different device_id, the previous device is messaged and removed. Omit it and that enforcement silently does nothing: the check returns early, logs nothing, and the old device stays signed in.
client_ipstringRecommandéThe END USER's public IP address, forwarded from your server. We see the address of whoever calls this endpoint — which, once you mint from your backend, is your data centre for every one of your users. That address decides the country we stamp on the participant AND which media node a new room opens on, so leaving it out can seat a Riyadh audience next to your server instead of next to them. Only honoured on a server-authenticated request (never app_key, where the handset's own address is already correct), and a private or malformed value is ignored rather than rejected.
device_modelstringRecommandée.g. SM-A175F. Feeds per-handset quality analysis — which models have audio or video trouble.
osstringRecommandéandroid | ios.
os_versionstringRecommandée.g. 14.
app_versionstringRecommandéYour app's version, so a regression can be traced to a release.
display_namestringOptionnelShown to other participants. Omit it and the name stays empty — we never substitute the user id for it.
rolestringOptionnelOnly honoured from a server-signed request, and only while your project still carries the client-asserted-role exception. The supported path is PUT /rooms/:room/participants/:id/role.
typestringOptionnelaudio_room | live_stream. Legacy kits send `service` (+ `kind`) instead and the type is derived.

Sur votre serveur

Le secret vit ici et nulle part ailleurs. Les champs signalés viennent de l'app — votre serveur ne peut pas les deviner.

mint-token.js
// Your backend — the app never sees the server secret.
const res = await fetch("https://engine.udt-stream.com/api/v1/token", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-App-Secret": process.env.UTD_SERVER_SECRET,   // never ship this in the app
  },
  body: JSON.stringify({
    user_id: currentUser.id,
    room_id: roomId,

    // 🔴 The user's own IP, not your server's. Without it every user of yours
    // is placed and geo-located as if they sat in your data centre.
    client_ip: req.headers["x-forwarded-for"]?.split(",")[0]?.trim() ?? req.ip,

    // 🔴 Forwarded FROM THE APP. Your server cannot know these on its own,
    // and without device_id one-account-one-device stops working for your users.
    device_id: body.device_id,
    device_model: body.device_model,
    os: body.os,
    os_version: body.os_version,
    app_version: body.app_version,
  }),
});

Dans votre app

Envoyez les infos de l'appareil à votre propre backend, qui les relaie. L'identifiant doit rester stable entre les redémarrages.

request_token.dart
// Your app — send the device facts to YOUR backend, which forwards them to us.
final deviceId = await MyDeviceIdentity.stableId(); // persisted, survives app restarts
await myApi.post("/rooms/$roomId/token", body: {
  "device_id": deviceId,
  "device_model": deviceInfo.model,
  "os": Platform.isAndroid ? "android" : "ios",
  "os_version": deviceInfo.version,
  "app_version": packageInfo.version,
});

Codes de refus (403)

Chaque refus porte un code. Lisez-le — seul le premier doit produire un message « vous avez été retiré ».

CodeSignificationQue faire
user_bannedThis user is banned from this room.Show them they were removed. This is the ONLY code that should produce that message.
room_type_disabledThe project does not have this room type enabled.A configuration problem, not a user problem. Never show a removal notice.
streaming_disabledThe streaming service is not enabled for this project.Same — configuration, not the user.
appkey_identity_mint_disabledYou tried to mint an identity-bearing token with the publishable app_key.Mint from your backend with the server secret instead. This is the path this page describes.

Modes d'authentification

Le moteur enregistre le mode à chaque connexion, pour que vous puissiez vérifier sur quel chemin vous êtes réellement.

secret / signature / bearer

Your backend, authenticated with your server secret. The recommended path.

app_key

The device, using the publishable app key. The legacy path — being closed.

Prêt à construire avec UTD ?

Créez votre compte, alimentez votre portefeuille principal et activez les services dont vous avez besoin.