Login State

The Login state is reached when a client sends a Handshake with Next State = 2 (or 3 for transfer). During Login the server authenticates the player against the Mojang session servers (in online mode), optionally enables packet compression, optionally exchanges plugin-defined query payloads, and finally hands the client a GameProfile. The state ends when the client sends Login Acknowledged, at which point both sides switch to Configuration.

See Data Types for primitive encodings, Connection Lifecycle for the surrounding state diagram, and Text Component for the reason field of Disconnect.

ID Name Direction
0x00 Disconnect (Login) Client-bound
0x01 Hello (Encryption Request) Client-bound
0x02 Game Profile (Login Success) Client-bound
0x03 Login Compression (Set Compression) Client-bound
0x04 Custom Query (Login Plugin Request) Client-bound
0x05 Cookie Request Client-bound
0x00 Hello (Login Start) Server-bound
0x01 Key (Encryption Response) Server-bound
0x02 Custom Query Answer (Login Plugin Response) Server-bound
0x03 Login Acknowledged Server-bound
0x04 Cookie Response Server-bound

Authentication & Encryption Flow

The Login state implements an asymmetric-key key-exchange that yields a shared 16-byte AES key, plus an out-of-band check against https://sessionserver.mojang.com that proves the joining client owns the Mojang account whose username it claims.

  1. Login Start. The client sends Hello (Login Start) with the chosen username and the player's offline-or-cached UUID.
  2. Compression (optional). If the server has a non-negative compression threshold configured, it sends Login Compression. All subsequent packets — in this state and every later state — are framed using the compressed framing described in the Overview.
  3. Encryption Request. In online mode, the server generates a random 4-byte verify token, picks (or reuses) a 1024-bit RSA keypair, and sends Hello (Encryption Request) containing its server-id string, the public key in X.509 SubjectPublicKeyInfo encoding, the verify token, and the shouldAuthenticate flag.
  4. Encryption Response. The client generates a random 16-byte AES secret, encrypts both the secret and the verify token with the server's RSA public key, and replies with Key (Encryption Response). On receiving it the server decrypts both fields, verifies the token matches the one it sent, and from that point on encrypts every byte of the framed stream with AES/CFB8 keyed by the shared secret. The client switches its own cipher state symmetrically.
  5. Mojang session check. If shouldAuthenticate was true, the server now computes a SHA-1 digest over serverId || sharedSecret || serverPublicKeyBytes (concatenated raw bytes), formats the digest as a signed big-integer two's-complement hexadecimal string (the famous "Notchian hash" — leading minus sign for negative digests, no zero-padding), and queries https://sessionserver.mojang.com/session/minecraft/hasJoined?username=<name>&serverId=<hash>. A 200 OK response carries the authoritative GameProfile (UUID + skin/cape properties); anything else means the client failed authentication and must be disconnected.
  6. Login Plugin Query (optional). Either before or after authentication the server may send any number of Custom Query packets. Each carries a transaction ID and an opaque payload identified by a namespaced ID; the client replies with a matching Custom Query Answer. Used by Velocity/BungeeCord modern forwarding.
  7. Login Success. With a profile in hand the server sends Game Profile (Login Success) carrying the full GameProfile.
  8. Login Acknowledged. The client confirms receipt with Login Acknowledged; both sides switch to Configuration.

If at any step the server needs to abort, it sends Disconnect (Login) with a Text Component describing the failure and closes the socket. Cookies (see Store Cookie) may be requested in the Login state with Cookie Request; this is most useful immediately after a Transfer-initiated reconnect.


Client-bound

0x00 - Disconnect (Login)

Packet ID: 0x00 · State: Login · Bound To: Client

Field Type Notes
Reason JSON Text Component The disconnect message shown on the client's "Disconnected" screen. Encoded as a JSON string (not as the binary NBT component used in Configuration/Play) because the client may not yet have a registry context to decode NBT.

Semantics. Server-initiated termination of the Login state. The connection is closed immediately after sending. Equivalent in role to the Configuration/Play Disconnect but with a JSON-string payload.

0x01 - Hello (Encryption Request)

Packet ID: 0x01 · State: Login · Bound To: Client

Field Type Notes
Server ID String (20) A short ASCII identifier salted into the Mojang hasJoined hash. Vanilla servers send the empty string.
Public Key Byte Array (VarInt-prefixed) The server's RSA-1024 public key, in X.509 SubjectPublicKeyInfo DER form.
Verify Token Byte Array (VarInt-prefixed) A 4-byte random nonce. The client must echo it back (encrypted) in Key so the server can prove the response wasn't replayed.
Should Authenticate Boolean When true, the server will perform the Mojang session check after decrypting Key. When false, the server skips the session call (used by velocity-style forwarding).

Semantics. Sent after Hello (Login Start) when the server is in online mode. After this packet the next expected serverbound packet is Key.

0x02 - Game Profile (Login Success)

Packet ID: 0x02 · State: Login · Bound To: Client

Field Type Notes
Game Profile GameProfile The authenticated profile: UUID (16 bytes), name (String, 16), and an array of (name, value, optional signature) properties. The textures property carries the player's skin/cape. See Data Types.

Semantics. Terminal client-bound packet of the Login state. The server stops handling Login packets after sending it and waits for Login Acknowledged.

0x03 - Login Compression (Set Compression)

Packet ID: 0x03 · State: Login · Bound To: Client

Field Type Notes
Threshold VarInt Minimum uncompressed packet size, in bytes, that triggers zlib compression. A value < 0 disables compression entirely.

Semantics. When sent, both sides immediately switch to the compressed framing described in the Overview. Sent at most once per connection, and only before Game Profile.

0x04 - Custom Query (Login Plugin Request)

Packet ID: 0x04 · State: Login · Bound To: Client

Field Type Notes
Transaction ID VarInt Unique per outstanding query; the client must echo it in its Custom Query Answer.
Channel Identifier Namespaced channel identifying the plugin protocol.
Data Byte Array (no length prefix; consumes the rest of the packet) Plugin-defined payload. Maximum 1 048 576 bytes.

Semantics. Lets the server query the client for plugin-defined information before authentication completes. Most commonly used by proxies for modern player-info forwarding.

Packet ID: 0x05 · State: Login · Bound To: Client

Field Type Notes
Key Identifier The cookie key whose value the server wants.

Semantics. Asks the client to return a previously-stored cookie (see Store Cookie). The client must reply with Cookie Response. Useful immediately after a Transfer so the new server can recover the previous server's session token.


Server-bound

0x00 - Hello (Login Start)

Packet ID: 0x00 · State: Login · Bound To: Server

Field Type Notes
Name String (16) Player username chosen for this session. Servers in online mode treat this as a claim to be verified by the Mojang session check.
Player UUID UUID The client-known UUID for this profile. In online mode it is overwritten by the authoritative UUID returned by Mojang; in offline mode the server typically derives the UUID from the username via UUID.nameUUIDFromBytes("OfflinePlayer:<name>").

Semantics. First packet of the Login state. Triggers the server to either send Hello (Encryption Request) (online mode) or skip straight to Login Compression followed by Game Profile (offline mode).

0x01 - Key (Encryption Response)

Packet ID: 0x01 · State: Login · Bound To: Server

Field Type Notes
Shared Secret Byte Array (VarInt-prefixed) The 16-byte AES shared secret, RSA-encrypted with the server's public key from Hello (Encryption Request).
Verify Token Byte Array (VarInt-prefixed) The verify token the server sent, RSA-encrypted with the same key. The server compares the decrypted plaintext byte-for-byte to detect MITM/replay.

Semantics. Concludes the encryption handshake. After receiving and validating it the server keys its AES/CFB8 cipher and either runs the Mojang session check or, if shouldAuthenticate was false, proceeds straight to Game Profile.

0x02 - Custom Query Answer (Login Plugin Response)

Packet ID: 0x02 · State: Login · Bound To: Server

Field Type Notes
Transaction ID VarInt Echoes the ID from the corresponding Custom Query.
Successful Boolean (encoded via Optional prefix) true if the client understood the channel and provides a payload below; false otherwise (the Data field is absent in that case).
Data Byte Array (consumes rest of packet) Plugin-defined response payload, present only when Successful is true. Maximum 1 048 576 bytes.

Semantics. Sent in reply to a Custom Query. Multiple may be in flight; the server matches them by Transaction ID.

0x03 - Login Acknowledged

Packet ID: 0x03 · State: Login · Bound To: Server

This packet has no fields.

Semantics. Terminal server-bound packet of the Login state. On receipt the server switches its connection state to Configuration; the client must do the same immediately after sending. Sent by the client in response to Game Profile.

Packet ID: 0x04 · State: Login · Bound To: Server

Field Type Notes
Key Identifier Echoes the key from the Cookie Request.
Payload Optional Byte Array (VarInt-prefixed, max 5120 bytes) The stored cookie value, or absent if the client has no value for that key.

Semantics. Sent in reply to Cookie Request. The payload is opaque to the client — it merely echoes whatever a server previously stored with Store Cookie.