Authentication is split into two distinct phases. First, the client exchanges credentials with the HTTP AuthServer (ASP.NET Minimal API) to receive anDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/kenzz55/ue5-iocp-mmo-server/llms.txt
Use this file to discover all available pages before exploring further.
AccessToken and, after selecting a game server, a short-lived EnterToken. Second, the client opens a TCP connection to the chosen game server and presents that EnterToken in a C_EnterGameReq packet. Only after the game server validates the token against Redis does it admit the session and assign a UDP port for positional updates.
Phase 1: HTTP AuthServer
The AuthServer exposes four HTTP endpoints backed by MariaDB (account/character data) and Redis (token storage). All request and response bodies are JSON.Endpoints
POST /auth/register
Create a new account. The server hashes the password with Response —
Returns
Pbkdf2PasswordHasher (PBKDF2-SHA256, 210 000 iterations, 16-byte salt, 32-byte key) before storing it.Request body4–64 characters.
8–128 characters.
2–32 characters. Defaults to the account name when omitted.
BasicResponse
Whether the account was created.
Human-readable status string.
400 Bad Request for invalid field lengths and 409 Conflict when the account name is already taken.POST /auth/login
Validate credentials and receive an Response —
Returns
AccessToken stored in Redis with a TTL of AccessTokenMinutes (default 60 minutes).Request bodyRegistered account name.
Plain-text password; verified with constant-time PBKDF2 comparison.
AuthResponse
Login outcome.
Numeric account identifier.
64-character hex token;
null on failure.Status string.
401 Unauthorized for wrong credentials. When DuplicateLoginPolicy is InvalidatePrevious (default), any existing session token is revoked before issuing a new one; when RejectNew, the login is rejected with 409 Conflict if an active session already exists.GET /servers
List all registered game servers. No authentication required.Response — array of
ServerDto
Unique server identifier.
Display name.
Public IP address.
TCP port.
Current connected player count.
Capacity limit.
When
true, the server rejects new connections.POST /auth/select-server
Exchange an Response —
Returns
AccessToken for a short-lived EnterToken (TTL = EnterTokenSeconds, default 60 seconds) bound to a specific server and character. The server creates a default character automatically if none exists for this account + server pair.Request bodyToken received from
POST /auth/login.Target server identifier from the server list.
SelectServerResponse
Operation outcome.
IP address for the TCP game connection.
TCP port for the game connection.
64-character hex token; valid for 60 seconds.
Character to enter the world with.
Status string.
401 for an invalid access token, 404 if the server ID does not exist, and 409 if the server is under maintenance.Phase 2: TCP EnterGame
Once the client has a TCP connection to the game server, it sendsC_EnterGameReq (packet ID 0x0201). The server calls RedisTokenValidator::ValidateAndConsumeEnterToken(), which atomically reads and deletes the game:enter:<token> key from Redis. Consuming the key on first use prevents replay attacks.
C_EnterGameReq — protobuf
S_EnterGameRes — protobuf (packet ID 0x0202)
GameWorld, loads inventory from MariaDB asynchronously, and pushes S_InventorySnapshot (0x0251) as soon as the load completes.
Phase 3: UDP Bind
After receivingS_EnterGameRes, the client binds a UDP socket and sends C_UdpHelloReq (packet ID 0x0204) to register its UDP endpoint with the server.
C_UdpHelloReq — protobuf
S_UdpHelloRes — protobuf (packet ID 0x0205)
server_time_ms is used by the client to seed its clock-synchronisation baseline for movement prediction.
Token Storage
| Token | Redis key pattern | TTL source | Default |
|---|---|---|---|
| AccessToken | auth:access:<token> | TokenOptions.AccessTokenMinutes | 60 min |
| Session marker | account:session:<accountId> | same as AccessToken | 60 min |
| EnterToken | game:enter:<token> | TokenOptions.EnterTokenSeconds | 60 s |
DuplicateLoginPolicy setting in appsettings.json controls what happens when a second login arrives for an already-authenticated account:
appsettings.json (Tokens section)
InvalidatePrevious(default) — the oldauth:access:<token>key is deleted before issuing a new token.RejectNew— ifaccount:session:<accountId>exists the login returns409 Conflict.
Password Hashing
Passwords are hashed byPbkdf2PasswordHasher using RFC 2898 / PBKDF2 with SHA-256. The stored hash string has the format:
CryptographicOperations.FixedTimeEquals to prevent timing-based enumeration of valid accounts.
The legacy TCP authentication packets —
C_LoginReq (0x0101), S_LoginRes (0x0102), C_RegisterReq (0x0103), S_RegisterRes (0x0104), C_ServerListReq (0x0111), S_ServerListRes (0x0112), C_SelectServerReq (0x0121), S_SelectServerRes (0x0122) — are still declared in Protocol.h and Packet.proto for backward compatibility but are not processed by the game server. All authentication must go through the HTTP AuthServer.