Player identity & sessions
One player can have several identities at the same time. They answer different questions, and mixing them creates subtle reconnect and security bugs.
One hero, three identities: the connection and participant change on reconnect; the account remains the durable player identity.
The three identities
Section titled “The three identities”| Identity | Plain-English meaning | Lifetime |
|---|---|---|
ConnectionId |
Which socket is carrying bytes right now? | One transport connection |
ParticipantId |
Which live realtime participant sent this message? | One accepted connection |
Account session + user_id |
Which durable player account authenticated? | Across reconnects until the session expires/revokes |
The first two are local, temporary routing identities. The account is the player identity you use for storage, friends, groups, wallet data, and other durable services.
Guest or authenticated player
Section titled “Guest or authenticated player”Every realtime connection starts with KIND_AUTH.
- An empty body asks to join as a guest. This works only when the server
allows guests. Runtime
ctx.user_idis absent. - A session token binds the new participant to the account that received the
token from device/custom authentication. Runtime
ctx.user_idis present.
Both paths still get a fresh ParticipantId for realtime sender tags.
Login and connect, step by step
Section titled “Login and connect, step by step”- The client authenticates a device/custom identity over HTTP.
- Citadel returns an access token and durable
user_id. - The client opens a realtime transport.
- The client sends the access token in its first reliable
KIND_AUTHenvelope. - Citadel validates the token and binds the account to a fresh participant.
- The participant can now join rooms and call authenticated game services.
This split is intentional: HTTP creates the account session; the realtime handshake proves that the new socket may use it.
Reconnect without identity confusion
Section titled “Reconnect without identity confusion”After a disconnect:
- the old
ConnectionIdis gone; - the old
ParticipantIdis gone; - room membership and live presence are gone;
- the account remains the same if the client authenticates again with a valid session token.
Never store durable player progress under ParticipantId. Store it under the
authenticated user_id.
Token security in plain English
Section titled “Token security in plain English”Treat a session token like a password. Keep it out of logs, send it only over an authenticated connection, and discard it when the session ends. Its serialized shape is an implementation detail: clients should store and return the token, not parse it or try to recreate it from a user id.
Citadel redacts token secrets in logs and validates expiry/revocation at connect. Invalid tokens return a deliberately vague failure so attackers cannot discover which tokens exist. Refresh credentials rotate: after a successful refresh, save the returned access/refresh pair and discard the old pair. A player can also revoke a single session through the player HTTP logout endpoint.
Current limits
Section titled “Current limits”- A reconnect always creates a new realtime participant.
- The current session-token index is in process, so tokens do not survive a server restart; the client authenticates again over HTTP.
- Connect-time validation ships. Active mid-connection expiry/revocation enforcement remains planned.
Related
Section titled “Related”- Authentication reference — exact HTTP and realtime contracts.
- Manage a player session — refresh, profile, known-player lookup, and logout.
- Gateway, rooms & relay — how accepted participants are routed.
- Messages & envelopes — how sender tags travel.