Resource: Realtime (transport access)
Tag: Realtime · Modules: realtime, room (LiveKit)
Realtime owns the tokens to connect to the realtime transports — neither is domain-specific, and neither
names its vendor (C6). The conference token joins a space's live audio/video session (LiveKit today —
the transport is an implementation detail, kept off the wire so it can change without a contract break); the
Centrifugo connection token authenticates the single WebSocket that both Chat and Presence ride.
(Chat messaging → chat.md; user-status presence → presence.md.)
The Centrifugo channel/connection model is owned by
centrifugo_chat_poc.md(§3 end-to-end flows — connection + subscription tokens and the channel scheme; §5.1 namespaces) — this file maps only the client-facing token endpoints onto the conventions.
Transports & concerns (the realtime cluster — three tags)
The cluster splits by domain concern, not by transport — the shared Centrifugo connection sits here in
Realtime, while the two things that ride it are their own resources/tags.
| Concern | Transport | Tag | Notes |
|---|---|---|---|
| Space video/audio + room presence (the 2D space) | LiveKit + Supabase room-presence | Realtime | stays (design R1; out of Centrifugo scope) |
| Centrifugo connection — the single WS both chat & presence ride | Centrifugo | Realtime | the connection token is the shared transport credential — not chat-owned |
| Chat messaging (conversations, messages, …) | Centrifugo chat: channels | Chat | chat.md — per-conversation subscribe-token |
| User-status presence (online/away/busy, "appear offline") | Centrifugo status: channels | Presence | presence.md — cross-cutting (space occupants, member sidebar, profile cards) |
Operations
The connection token's channels claim auto-subscribes only identity channels (user:/org:/role:)
server-side; conversation (chat:) and status (status:) channels are authorized separately (Chat's
subscribe-token and the internal subscribe-proxy respectively — see those files).
| OperationID | Method + Path | Security | Notes |
|---|---|---|---|
get-conference-token | POST /realtime/conference-token | cookie | token to join a space's live A/V conference; LiveKit today (vendor kept off the wire, C6); was /livekit/room-auth (N3) |
get-connection-token | POST /realtime/connection-token | cookie | Centrifugo connection JWT (identity channels only, short TTL); refreshed via centrifuge-js getToken |
// get-conference-token — Request
{ "spaceId": "string" } // the space whose realtime A/V conference to join (N1 settled the field name → spaceId)
// Response
{ "token": "string", "expiresAt": "RFC3339" } // C3 (was unix int64 in the old realtime TokenResponse)
// get-connection-token — Request body empty {} (identity from the cookie/session)
// Response
{ "token": "string", "expiresAt": "RFC3339" } // C3 — short TTL; `channels` claim = user:/org:/role: only
Conventions / module notes
- Timestamps: token
expiresAtis RFC3339 (C3) — was unix int64 in the old realtimeTokenResponse. - Paths:
*-tokenis the sanctioned verbless artifact-noun terminal (C1b). - Module: the Supabase token minter (
realtime/service/generatetoken.go) adapts into the Centrifugo connection-token service (different claims/secret) — it does not disappear, and it lives here (it authenticates the shared connection used by both chat and presence), not underChat. One Go service may mint both Centrifugo JWTs (connection + subscription); the contract splits by domain/consumer. - The A/V conference token (LiveKit today) stays here under
Realtime(joining is not a space CRUD action — N3); its vendor name is deliberately absent from the wire (C6), so the transport can change freely.