Tokens im eigenen Backend ausstellen
Der unterstützte Weg, ein Join-Token auszustellen — und das eine Feld, dessen Fehlen die Einzelsitzungs-Durchsetzung stillschweigend abschaltet.
Warum im Backend?
Ihr Server-Secret gehört nie in die App. Jeder im APK mitgelieferte Schlüssel lässt sich extrahieren und für Identitätsmissbrauch nutzen.
Gerätedaten weiterreichen
Ihr Server sieht das Gerät nicht. Die App schickt diese Werte an Ihren Server, der sie im selben Request weitergibt.
Der Ausfall ist stumm
Ohne device_id kehrt die Prüfung ohne Fehler und ohne Log früh zurück. Das Token gelingt, der Schutz ist schlicht aus.
Gemessen, nicht vermutet
Über drei Stunden echter Joins: im Backend ausgestellte Tokens ergaben 3.224 Joins — 100 % ohne Geräte-ID. Im Kit ausgestellte Tokens 1.641 Joins — 0 %.
Felder der Token-Anfrage
POST an /api/v1/token mit Ihrem Server-Secret im Header.
| Feld | Stufe | Bedeutung |
|---|---|---|
user_idstring | Erforderlich | Who the token is for. Your own user id. (Previously `identity` — still accepted.) |
room_idstring | Erforderlich | Which room they are joining. (Previously `room_name` — still accepted.) |
device_idstring | Empfohlen | 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_ipstring | Empfohlen | 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_modelstring | Empfohlen | e.g. SM-A175F. Feeds per-handset quality analysis — which models have audio or video trouble. |
osstring | Empfohlen | android | ios. |
os_versionstring | Empfohlen | e.g. 14. |
app_versionstring | Empfohlen | Your app's version, so a regression can be traced to a release. |
display_namestring | Optional | Shown to other participants. Omit it and the name stays empty — we never substitute the user id for it. |
rolestring | Optional | Only 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. |
typestring | Optional | audio_room | live_stream. Legacy kits send `service` (+ `kind`) instead and the type is derived. |
Auf Ihrem Server
Das Secret liegt nur hier. Die markierten Felder kommen aus der App — Ihr Server kennt sie nicht von selbst.
// 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,
}),
});In Ihrer App
Schicken Sie die Gerätedaten an Ihr eigenes Backend, das sie weiterreicht. Die Geräte-ID muss Neustarts überdauern.
// 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,
});Ablehnungscodes (403)
Jede Ablehnung trägt einen code. Lesen Sie ihn — nur der erste darf je „Du wurdest entfernt" anzeigen.
| Code | Bedeutung | Was tun |
|---|---|---|
user_banned | This user is banned from this room. | Show them they were removed. This is the ONLY code that should produce that message. |
room_type_disabled | The project does not have this room type enabled. | A configuration problem, not a user problem. Never show a removal notice. |
streaming_disabled | The streaming service is not enabled for this project. | Same — configuration, not the user. |
appkey_identity_mint_disabled | You 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. |
Auth-Modi
Die Engine protokolliert den Auth-Modus bei jedem Join, damit Sie prüfen können, auf welchem Weg Sie wirklich sind.
secret / signature / bearerYour backend, authenticated with your server secret. The recommended path.
app_keyThe device, using the publishable app key. The legacy path — being closed.
Bereit, mit UTD zu entwickeln?
Erstellen Sie Ihr Konto, laden Sie Ihre Master-Wallet auf und aktivieren Sie die Dienste, die Sie brauchen.