-
Notifications
You must be signed in to change notification settings - Fork 1
AUTH HANDSHAKE
This page covers what happens between a transport opening and the moment a session is allowed to present credentials: the connection state machine and the handshake packets. Read AUTH-CONNECTIONS for the transport boundary, continue with AUTH-SECURITY for byte wrapping, and use AUTH-SSO for the login itself.
Every session (networking/connection) moves through an explicit lifecycle, and every packet handler declares which states it accepts. A packet arriving in the wrong state is a protocol error, not a judgment call:
Created → Handshaking → (Securing ⇄ Handshaking) → Authenticating → Authenticated → Connected
Handlers register with state guards, so the registration itself is the security model:
_ = registry.Register(inrelease.Header, Release,
netconn.AllowStates(netconn.StateCreated, netconn.StateHandshaking), netconn.AllowUnauthenticated())
_ = registry.Register(inticket.Header, Ticket(authenticator),
netconn.AllowStates(netconn.StateHandshaking), netconn.AllowUnauthenticated())Only a handful of packets carry AllowUnauthenticated; everything else implicitly requires an authenticated session. That's why no realm handler ever re-checks "is this user logged in": a packet that reaches a realm handler could not have arrived otherwise.
Transitions are validated too: the state machine only permits legal moves (Created → Handshaking, Handshaking → Securing, back, and forward into authentication), and an illegal transition disconnects with a typed reason instead of leaving the session in an undefined phase.
A Nitro client currently opens the WebSocket (GET /ws) and sends a short metadata sequence before authenticating. The shared session would accept the same packet sequence from any future transport adapter. Pixels accepts, in the early states:
| Packet | Purpose | What Pixels does |
|---|---|---|
| Release version | Client build identification | Decoded and accepted |
| Client variables | Asset/config URLs the client is using | Decoded and accepted |
| Policy probe | Legacy cross-domain policy request | Decoded and accepted |
| Machine ID | A persistent per-device identifier | Validated; a missing or malformed ID gets a server-issued replacement |
| Diffie init / complete | In-protocol key exchange | See AUTH-SECURITY |
| SSO ticket | The actual login | See AUTH-SSO |
The machine ID exchange deserves a note: when the client presents nothing usable, Pixels generates a random hex identifier and sends it back, so every device ends up with a stable ID without any of it being trusted for authentication. It's device telemetry, not identity.
The handshake handlers are deliberately outside any gameplay realm, in internal/realm/connection/handlers/handshake and internal/realm/connection/handlers/security. They are the only handlers in the codebase allowed to run before authentication. handshake owns client metadata and key exchange packets. security owns machine identity and the SSO ticket. Neither package imports the WebSocket adapter.
Pixels
Getting Started
Architecture
Architecture Internals
Authentication
Users
Navigator
Inventory
Furniture
Rooms
Decoration
Games
Plugins
- PLUGINS-OVERVIEW
- PLUGINS-CREATING
- PLUGINS-LISTENERS
- PLUGINS-EVENTS-REALMS
- PLUGINS-EVENTS-ECONOMY-ROOMS
- PLUGINS-EVENTS-MODERATION-TRADES
- PLUGINS-EVENTS-COMMERCE-WORLD
- PLUGINS-EVENT-FURNITURE-MOVE
- PLUGINS-EVENT-FURNITURE-PICKUP
- PLUGINS-EVENT-ROOM-CREATE
- PLUGINS-EVENT-MARKETPLACE-LIST
- PLUGINS-EVENT-MARKETPLACE-BUY
- PLUGINS-EVENT-PLAYER-PROFILE-UPDATE
- PLUGINS-EVENT-BOT-SPEECH
- PLUGINS-EVENT-GROUP-MEMBERSHIP-CHANGE
- PLUGINS-EVENT-MESSENGER-FRIEND-REQUEST
- PLUGINS-EVENT-MESSENGER-FRIEND-ACCEPT
- PLUGINS-EVENT-CRAFTING-CRAFT
- PLUGINS-WIRED
- WIRED
- PLUGINS-COMMANDS
- PLUGINS-SDK
- PLUGINS-DEPLOYMENT