This page lists every credential in Livqeno, what each one can do, and the few rules that keep them safe. For each rule, it says what attack the rule stops, so you can judge your own design against it.
Where this fits: read this before you go to production, after your token endpoint works. The Production checklist points here.
Four credentials
| Credential | Held by | Lifetime | Can make other credentials? |
|---|---|---|---|
| Dashboard session (JWT) | A developer, the CLI | 12h | No |
| Project API key | Your backend | Until revoked | Yes, tokens |
| RTC token | A browser or device | ≤ 6h | No |
| Chat token | A browser or device | ≤ 6h | No |
Livqeno signs each kind with its own secret and marks it with what it's for. So one credential can never be used as another:
- A dashboard session can't be used as a chat token.
- A chat token can't be used as an RTC token, and the other way around.
The threat this covers: if one kind of credential is ever exposed, the damage stays inside that kind.
The one rule
The threat: anything that reaches a user's device can be read by that user, and anything in a public place can be found by bots that scan for keys.
Your app gets a token instead. If a token leaks, the damage is limited to one room or a few conversations, and only until it expires. If an API key leaks, there is no limit until you revoke it.
Why the app can't make its own token
Then the app could say who it is. And it could say it's someone else: Bob's app could ask for a token as Alice and read her private chat.
So your backend takes the user's identity from its own login session and sends it to Livqeno. Livqeno signs it. After that, nobody can change it.
What the SDKs promise
- The API key is kept in a private field. It never appears in
JSON.stringify(), a Pythonrepr(), Go's%+v, a JavatoString()or a PHPvar_dump(). - It is never logged, at any level.
- It is never put in an error. Errors carry only
{message, code, requestId}. - No SDK hands out a TURN credential you didn't already get from a mint response.
Transport
Use https:// and wss:// (encrypted WebSockets) in production.
The threat: on shared Wi-Fi, an unencrypted connection can be read by anyone nearby, tokens included.
The chat token is sent in the WebSocket URL. Browsers can't add an
Authorization header to a WebSocket. The downside: URLs can end up in proxy
logs and browser history. That's why chat tokens are short-lived, revocable,
and narrow, and why plain ws:// is for local development only.
Origin checks
A browser tells servers which website a request comes from, in the Origin
header (for example https://app.example.com). Livqeno checks it against the
project's Allowed Origins list (Settings → Security → Allowed Origins).
The threat: someone copies a token and uses it from their own website. With your sites listed, a page on any other site is refused.
- A mismatch is refused with
ORIGIN_NOT_ALLOWED(chat close code4403). - Web pages can't fake
Origin. - A missing
Originis allowed, because non-browser clients don't send one. They still need a valid token. - Wildcards aren't supported. List each site.
Details: Browser security & CORS.
Webhook receivers
Always check the signature. Your webhook URL is public, so without the check your endpoint accepts anything anyone sends, like a fake "message created" or "stream ended" event. Three rules:
- Compare signatures in constant time. A normal comparison stops at the first wrong character, and the timing can leak the right answer.
- Sign the raw request body. Re-encoding the JSON changes the bytes, and then the signature never matches.
- Reject old timestamps. This stops someone replaying a real delivery they captured earlier.
Webhooks has example code.
Known gaps
Be aware of these when you assess your own risk:
- Webhook URL checks only look at the hostname. Livqeno blocks non-HTTP
schemes, loopback, and private IP addresses, and requires
https://in production. It does not look up DNS. A hostname that points to a private address still passes, and so does a redirect to one. Block that with network rules on your side. - Revoking an RTC token is best-effort. It blocks new connections and
ends sessions running on that token (
TOKEN_REVOKED), but a session that refreshed onto a newer token is unaffected, and a Redis outage delays it. See RTC authentication → Revocation.
More in Known limitations.