Authority System¶
In a peer-to-peer game, every player runs their own copy of the game logic. This works well for cooperative or turn-based games, but some genres need a single source of truth -- one player whose copy of the game state is considered authoritative. Signal Fish Server provides an optional authority system that lets you designate exactly one player per room as the authority.
What is Authority?¶
Authority means one player acts as the trusted host for game-critical decisions: physics resolution, score keeping, anti-cheat validation, or any logic where conflicting results between peers would break the game. The other players send their inputs to the authority and accept its responses.
Signal Fish does not enforce what the authority player does with that role -- it simply tracks who holds authority and notifies all players when it changes. Your game code decides how to use it.
Enabling Authority¶
Authority is enabled by default. It is configured at room creation time
via the optional supports_authority field in the JoinRoom message:
omit it (or set true) to enable authority, set false to disable it.
The example below sets the field explicitly, which is equivalent to the
default:
{
"type": "JoinRoom",
"data": {
"game_name": "my-game",
"player_name": "Alice",
"max_players": 4,
"supports_authority": true
}
}
supports_authority defaults to true when omitted, so authority is
enabled and the creating player becomes the initial authority unless you
explicitly set supports_authority: false. In a room created with
supports_authority: false, AuthorityRequest messages are rejected
with the AUTHORITY_NOT_SUPPORTED error code.
How Authority Works¶
Initial Assignment¶
The first player to join a room with authority enabled becomes the
authority by default. When Alice creates the room above, her RoomJoined
response includes "is_authority": true, and all subsequent players who
join see her flagged as the authority in the current_players list.
Requesting Authority¶
Any player in the room can request authority by sending an
AuthorityRequest message:
The server responds directly to the requesting player with an
AuthorityResponse:
If the request is denied (for example, because another player already holds authority), the response includes a reason and the error code for that specific cause:
{
"type": "AuthorityResponse",
"data": {
"granted": false,
"reason": "Another player already has authority",
"error_code": "AUTHORITY_CONFLICT"
}
}
The code tells you whether retrying can ever succeed:
error_code |
Cause | Retry? |
|---|---|---|
AUTHORITY_CONFLICT |
Another member holds the role right now. | Yes — after an AuthorityChanged clears it. |
AUTHORITY_NOT_SUPPORTED |
The room was created with supports_authority: false. |
No — no member of this room can ever hold the role. |
AUTHORITY_DENIED |
You are not a member of the room, or you released a role you do not hold. | No — nothing about the room's state will change that. |
ROOM_NOT_FOUND |
The room disappeared before the authority transition committed. | Rejoin or create a room before retrying. |
NOT_IN_ROOM |
You are not in a room at all. | Join a room first. |
STORAGE_ERROR |
The server could not decide the request. | Yes — this is a transient server-side fault. |
INTERNAL_ERROR |
The request failed before storage was consulted. | Yes — this is a transient server-side fault. |
Broadcasting Authority Changes¶
When authority changes, every player in the room receives an
AuthorityChanged message. The you_are_authority field is personalized
per recipient:
Sent to the new authority:
{
"type": "AuthorityChanged",
"data": {
"authority_player": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"you_are_authority": true
}
}
Sent to all other players:
{
"type": "AuthorityChanged",
"data": {
"authority_player": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"you_are_authority": false
}
}
Releasing Authority¶
A player can release authority by sending become_authority: false:
This clears the authority role. All players receive an AuthorityChanged
message with authority_player set to null:
{
"type": "AuthorityChanged",
"data": {
"authority_player": null,
"you_are_authority": false
}
}
Authority Player Disconnects¶
If the authority player leaves or disconnects from the room, authority is
cleared -- there is no automatic reassignment. All remaining players
receive an AuthorityChanged message with authority_player: null, ordered
after the PlayerLeft that explains it. (One exception: if storage is
unavailable at the moment of the disconnect and the compensating release also
fails, the durable removal is retried in the background and the role is cleared
when that repair lands, without a further notification.) A member that reconnects
across the change is told the room's authority as it stands when it returns:
its Reconnected snapshot reports whether it holds the role (is_authority)
and flags the holder in current_players, and any buffered authority event
that snapshot already supersedes is not replayed. Your
game logic should handle this case, either by prompting another player to
claim authority or by pausing the game until someone does.
If the departed member reconnects while another player has since claimed the role, the successor keeps it: the returning member is restored as an ordinary, non-authority member.
Moderation Powers¶
The authority holds a set of moderation operations (v3 only, via the
room_operation_ids capability; see Protocol Reference):
KickPlayerremoves a seated player from the room — or tombstones this room's pending reconnection record. The target's connection closes with close code4007(kicked) unless the target is live in another room, the remaining members see the usualPlayerLeftroster delta, and the kicked seat is never reconnectable. Use it to evict a disruptive player instead of waiting for them to leave.BanPlayerevicts exactly likeKickPlayerand records the player id on the room's ban list: while the room lives, the banned id cannot rejoin it as a player or a spectator (BANNED).UnbanPlayerlifts a ban (idempotent). Bans are room-scoped and in-memory: they expire when the room dies, and no cross-room or cross-instance effect exists.RegenerateRoomCodereplaces the room code with a fresh one. Existing members stay connected; the old code stops resolving immediately. Use it when an invite code leaks: the room survives, and only holders of the new code can send new joiners. The rotation result (RoomCodeRegenerated) is delivered only to the authority, who shares the new code with future invitees out of band. The rotation is never broadcast: a member who stays connected keeps the stale code until the next snapshot, and a reconnecting member receives the current code inReconnected. A stale code is an unknown code: a join that names it opens a different room. No message queries the current code, and the transfer announcements carry no code. A role hand-over after a rotation needs the new code shared with the successor out of band first; otherwise the new authority holds only their join-time code and cannot invite (issue #566).SetRoomAccessseals the room behind a join password (or reopens it withnull). Sealed rooms refuse every join -- seated or spectator -- that does not present the password (PASSWORD_REQUIRED); a missing, a mismatched, and a stray password into an open room are indistinguishable. Current members and their reconnection tokens are unaffected. A pending reconnection record armed before the seal also restores its holder with no password:Reconnectcarries no password field, and resuming a prior membership through a live seat credential is not a fresh admission. (A ban is the tool that refuses restores.) The password is stored only as a salted hash. See Rooms and Lobbies for the client-side flow.TransferAuthorityhands the authority role to a seated member of your choice. Every member receives the usualAuthorityChangedbroadcast; the sender loses every authority capability (includingStartGameand the operations above) and the successor gains them. The transfer carries no room code: a successor who joined before a rotation still knows only their join-time code. Share the current code out of band before or with the transfer (issue #566). If the session is already running, the transfer moves the role but not the session's transport host (see below).
All of these are authority-only: a member that is not the authority receives
NOT_ROOM_AUTHORITY. The kicked or banned player cannot be the authority
itself.
Handing Over Authority Deliberately¶
TransferAuthority is the planned successor path: before you leave -- or
when the game should change hands -- name a seated member and the server
moves the role atomically (validated under the room's mutation gate, so the
successor cannot depart between validation and the grant). This is
stronger than the drop-and-claim dance (release the role, everyone races to
claim) and works even when no member was primed to claim: the departing
authority picks any seated member, including one that never requested the
role.
The Role and the Transport Host Are Not the Same Thing¶
When a v3 room finalizes, the server elects a transport host for the running session: the peer every other member connects to for P2P traffic (for a host/star topology) or the member that anchors the session. This election is recorded at finalize time and does not follow the authority role afterwards.
A mid-game TransferAuthority changes who moderates (kick, ban, room
access, room-code rotation, further transfers) and who may re-start or
manage the session -- it does not re-elect the transport host. After a
mid-game transfer, clients receive AuthorityChanged, while the session
plan keeps hosting on the finalize-time host. The host only moves when a
host-failover event happens: the elected host departs (or can no longer
run the session), and the server re-elects a host and re-emits fresh
session plans.
If your game wants the new authority to also become the transport host,
the simplest supported path is: have the old host leave (or reconnect the
session through a re-plan) after the transfer. Design your client to read
the transport host from the SessionPlan, not from the authority role.
Key Rules¶
- Only one player can hold authority at a time per room.
- Authority is enabled by default (
supports_authority: true); passsupports_authority: falseat room creation to disable it. - The first player to join becomes authority by default.
- Authority transfers are explicit via
AuthorityRequest. - Disconnection clears authority with no auto-reassignment.
- Authority status is included in the legacy
GameStartingpeer metadata so clients know who the authority is at game start. - Moderation is authority-only:
KickPlayer,RegenerateRoomCode,SetRoomAccess,BanPlayer,UnbanPlayer, andTransferAuthorityare refused withNOT_ROOM_AUTHORITYfor every other member, and rooms created withsupports_authority: falsehave no moderator at all. - A mid-game authority transfer moves the role, not the session's transport host: the host was elected at finalize time and only changes through host failover.
Use Cases¶
- Host migration -- If the current host drops out, another player requests authority and becomes the new host.
- Authoritative physics -- The authority player runs the physics simulation and broadcasts results to peers.
- Anti-cheat validation -- The authority cross-checks player inputs against game rules before accepting them.
- Asymmetric gameplay -- One player acts as the game master or dungeon master with elevated control.
When NOT to Use Authority¶
If your game is fully symmetric -- every peer runs identical logic and resolves conflicts through deterministic lockstep or rollback netcode -- you do not need the authority system. Skipping it simplifies your room setup and avoids unnecessary authority-related messages.
Next Steps¶
- Rooms and Lobbies -- Room lifecycle and the ready-up flow
- Reconnection -- What happens to authority during reconnection
- Spectator Mode -- Read-only observers who do not participate in authority