Concepts
How Thuum works
Domains, App Keys, tokens, claims, brokers and topics, and how one request is authorized.
The pieces#
| Concept | What it is |
|---|---|
| Domain | Your tenant, identified by a slug (acme). Every URL starts with it: /api/acme/…. Its keys, claims and data are isolated from every other Domain. |
| App Key | A secret credential of your Domain: an identity and a token lifetime. It grants nothing by itself, cannot be modified, and is shown in full only when created. |
| Token | A short-lived bearer credential exchanged from an App Key. Every REST request and WebSocket handshake presents one. |
| Claim | A named, reusable set of permissions linked to App Keys. There is one kind per area: Domain Claims, Event Broker claims, State Broker claims. |
| Broker | A real-time service: the Event Broker (events) and the State Broker (states). Each has its own REST routes, WebSocket and topics. |
| Topic | Where data lives in a broker: chat, chat:lobby, orders:1042. Levels are joined by : and form a hierarchy. |
App Keys#
An App Key is 80 lowercase hex characters: a 16-character selector, which is public and identifies the key in lists and URLs, followed by a 64-character secret.
3f9c1a7be04d52aa 9d0e…(64 hex)…41c7
└── selector ───┘ └──── secret ────┘- Thuum stores only a keyed hash of the key. Lose it and you create a new one.
- Its token TTL (1 second to 24 hours, 30 seconds by default) is how long tokens minted from it live.
- It is immutable: to change its name or TTL, create a new key and move the claim links to it (the console's Renew).
- It cannot be deleted while it is linked to a claim.
Tokens#
POST /api/{domain}/token with an App Key returns a token (a signed JWT) and its lifetime:
{ "data": { "token": "eyJhbGciOi…", "token_type": "Bearer", "expires_in": 30 } }- Present it as
Authorization: Bearer <token>on REST requests, or as?token=when opening a WebSocket (browsers cannot set headers on WebSockets). - It always expires, and cannot be refreshed: exchange the key again.
- It is a reference, not a bag of permissions: its subject is the key's selector. Permissions are looked up from the key's claims on every REST request, so changes apply immediately.
- A WebSocket checks the token once, at the handshake, and takes a snapshot of the claims. The connection outlives the token; reconnect to pick up permission changes.
Claims#
A key has at most one claim of each kind:
| Claim kind | Grants |
|---|---|
| Domain Claim | Management, per protocol: domain (App Keys, Domain Claims), event and state (their claims). |
| Event Broker claim | Event Broker access: retention configs (topic_flags) and data, per Main Topic. |
| State Broker claim | State Broker access: TTL and size configs (topic_flags) and states, per Main Topic. |
Permissions are bit flags, P W S R, the same everywhere. Details in
Claims and permissions.
Brokers#
The two brokers are independent: their topics, data, claims and WebSockets are separate. chat in
the Event Broker has nothing to do with chat in the State Broker.
| Event Broker | State Broker | |
|---|---|---|
| Unit | An event: type + JSON data, immutable | A state: key → JSON value, with a version |
| Write | publish | set, merge (JSON Merge Patch), delete, echo |
| Live | every event, to subscribers of the topic's family | every change, to subscribers of the topic's family |
| Read | history, newest first, within a retention window | one key, or a listing of a topic's subtree |
| Kept | the newest events, by count and age | the current value only, optionally with a TTL |
| WebSocket | /api/{domain}/event/connect | /api/{domain}/state/connect |
| REST | /api/{domain}/event/… | /api/{domain}/state/… |
Read more: Event Broker, State Broker.
How a request is authorized#
Every request with a token goes through the same steps:
- Domain: it must exist (
404) and be active (403). - Token: valid signature, not expired, and its key still exists in this Domain (
401). - Claim: the claim the route needs, looked up from the key's links. Management routes use the
Domain Claim's protocol; data routes use the broker claim. No linked claim:
403. - Flag: the bit the operation needs, on the topic's Main Topic. Missing:
403.
On a WebSocket, steps 1–3 run at the handshake and step 4 on every operation, answered with an
:error reply rather than closing the connection.
Responsibilities#
| Thuum | You |
|---|---|
| WebSocket servers, fan-out, delivery to every subscriber | Keep App Keys on your servers; give browsers tokens |
| Authentication of tokens, authorization by claims, tenant isolation | Decide which of your users may get a token (Thuum doesn't know your users) |
| Retention, pruning, versioning, atomic merges | Validate the data you read: anyone with write access can write anything |
| History for catch-up | Reconnect, catch up, de-duplicate (guide) |