Skip to content

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:

POST /login → 200
{
  "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.

Guest login (anonymous) — Godot 4 HTTPRequest
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.