03 — Logging in¶
The sample in chapter 02 plays on a local server with no identity — fine for a
listen-server on the same machine. For a real game you want a player identity: an access token
minted by the lattice-auth service. That token authenticates the player to the social service and
(via the director) to the game server.
The Lattice Godot binding is not involved in login at all — auth is plain JSON over HTTP. You call
it from Godot with the built-in HTTPRequest node (or HTTPClient). This chapter shows the
endpoints and a Godot HTTPRequest example.
Verified against: control-plane/lattice-auth/src/LatticeAuth/Program.cs,
control-plane/lattice-auth/src/LatticeAuth/Api/Contracts.cs; the binding surfaces no auth API
(bindings/lattice-godot/src/lattice_runner.cpp:27-96).
The auth endpoints¶
lattice-auth exposes these (bodies are snake_case JSON). In local dev it runs on port 3005.
| Endpoint | Body | Returns | Auth |
|---|---|---|---|
POST /guest |
{ region?, device_fingerprint? } |
token response | none |
POST /register |
{ email, password, region? } |
{ account_id } — no token |
none |
POST /login |
{ email, password, device? } |
token response | none |
POST /identity |
{ provider, ticket, device? } |
token response | none |
POST /platform |
{ provider, ticket, device? } |
token response | none |
POST /refresh |
{ refresh_token } |
token response | none |
GET /account |
— | account info | Bearer |
Verified against: lattice-auth/src/LatticeAuth/Program.cs:127-200 (/guest, /register, /login,
/platform, /identity, /refresh, /account); port from run-all.sh:24 (PORT_AUTH=3005).
The token response is:
{
"access_token": "eyJ…",
"refresh_token": "…",
"expires_in": 3600,
"account_id": "5f3c…"
}
Verified against: lattice-auth/src/LatticeAuth/Api/Contracts.cs (TokenResponse(access_token,
refresh_token, expires_in, account_id)).
/register does not return a token
Registration creates the account and returns only { account_id }. Call POST /login afterward to
get an access token.
Verified against: Program.cs:133-144.
Guest login from Godot with HTTPRequest¶
HTTPRequest is a Node; add it to your scene (or create it in code), fire request(), and read the
JSON in the request_completed signal.
extends Node
signal token_ready(access_token: String)
const AUTH_BASE := "http://localhost:3005"
@onready var http := HTTPRequest.new()
func _ready() -> void:
add_child(http)
http.request_completed.connect(_on_request_completed)
func guest_login(region: String = "eu") -> void:
var body := JSON.stringify({ "region": region })
var headers := ["Content-Type: application/json"]
var err := http.request(AUTH_BASE + "/guest", headers, HTTPClient.METHOD_POST, body)
if err != OK:
push_error("guest_login request failed to start: %d" % err)
func _on_request_completed(result: int, code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
if result != HTTPRequest.RESULT_SUCCESS or code != 200:
push_error("auth failed (result=%d http=%d)" % [result, code])
return
var data: Dictionary = JSON.parse_string(body.get_string_from_utf8())
var access_token: String = data.get("access_token", "")
token_ready.emit(access_token) # keep this for the director (chapter 04)
The email login variant is identical except you POST /login with a body of
{ "email": …, "password": … } and read the same token response.
Verified against: the request/response shapes in Contracts.cs; the handlers in Program.cs:127-156.
One HTTPRequest node = one in-flight request
A single HTTPRequest handles one request at a time and fires request_completed once. For
parallel calls, use several HTTPRequest nodes (or await each in turn). This is Godot's standard
HTTP node behaviour, not anything Lattice-specific.
What the token is for¶
Keep the access_token. You'll present it as a Bearer token to:
- the director (
/matchmake,/resolve) to find and join a game server — see chapter 04, and - the social service (friends/presence/parties) on port 3009.
Verified against: control-plane/lattice-director/src/LatticeDirector/Program.cs:141-160 (matchmake
requires a valid bearer); run-all.sh:29 (PORT_SOCIAL=3009).
Gotchas and honesty notes¶
Third-party sign-in is fail-closed by default
Steam/Epic/Google/etc. ticket verification (/identity, /platform) is rejected unless the
deployment opts into the dev/test stub verifier with the environment variable
LATTICE_ALLOW_STUB_VERIFIER=1. The stub does no real cryptography — it trusts a
"<provider>:<subject>" ticket — so it is strictly a development convenience. Email login and guest
login work without it.
Verified against: lattice-auth/src/LatticeAuth/Program.cs:39-51.
Rate limiting
/login, /register, /platform, /identity are limited to ~20 requests/min/IP; /guest to
~10/min/IP. A tripped window returns HTTP 429. An in-process test host disables this with
LATTICE_DISABLE_RATE_LIMIT=1.
Verified against: Program.cs:62-88.
There is no Godot login SDK — this is just HTTP
Unlike the .NET LatticeSocialClient SDK available to C# projects, there is no GDScript SDK for
auth/social. From Godot you call these REST endpoints directly with HTTPRequest, as above. (On the
Godot .NET build you could reference the LatticeSocialClient managed DLL, but that is a C#-only
convenience, not part of this binding.)
Verified against: absence of any auth/social caller under bindings/lattice-godot/.
Next: 04 — Lobbies & matchmaking, to turn that token into a game-server endpoint — and to read the honest status of how far that is wired for Godot.