03 — Logging in¶
The sample in chapter 02 connects with an arbitrary token to a local server —
fine for a listen-server on 127.0.0.1. 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.
This chapter shows two ways to get a token:
- the
LatticeSocialClientSDK (a .NET helper that wraps the calls), and - the raw REST endpoints (call them from Unity with
UnityWebRequestorHttpClient).
Verified against: control-plane/lattice-social-client/src/LatticeSocialClient.SignIn.cs,
control-plane/lattice-auth/src/LatticeAuth/Program.cs,
control-plane/lattice-auth/src/LatticeAuth/Api/Contracts.cs.
The SDK is a separate .NET library, not part of com.lattice.netcode
LatticeSocialClient lives in control-plane/lattice-social-client/ and is a standalone .NET
library. To use it in Unity you'd reference it as a managed DLL. If you'd rather not add a
dependency, the endpoints are plain JSON HTTP — call them directly with UnityWebRequest. Both
paths hit the same lattice-auth service and produce the same token.
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-190,
lattice-auth/src/LatticeAuth/Api/Contracts.cs:4-21; port from run-all.sh:24.
The token response is:
{
"access_token": "eyJ…",
"refresh_token": "…",
"expires_in": 3600,
"account_id": "5f3c…"
}
Verified against: Contracts.cs:17-21 (TokenResponse(access_token, refresh_token, expires_in, account_id)),
serialized with PropertyNamingPolicy = null at Program.cs:98.
/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.
Option A — the LatticeSocialClient SDK¶
Point the SDK at your auth deployment with UseAuth, then call one of the SignIn* methods. On
success the SDK applies the token as its own bearer identity automatically, so the very next
social call is authenticated.
using LatticeSocial.Client;
var social = new LatticeSocialClient(new Uri("http://localhost:3009")); // social service
social.UseAuth(new Uri("http://localhost:3005")); // auth service
// Guest (anonymous) — no credentials needed:
LatticeSession session = await social.SignInAsGuestAsync(region: "eu");
// …or email + password:
LatticeSession session = await social.SignInWithEmailAsync("player@example.com", "hunter2");
// …or a third-party ticket (Steam/Epic/Google/Microsoft/Apple):
LatticeSession session = await social.SignInWithThirdPartyAsync(IdentityProvider.Steam, ticket);
string accessToken = session.AccessToken; // pass this on to the director (chapter 04)
Verified against: LatticeSocialClient.SignIn.cs:27-83 (UseAuth, SignInAsGuestAsync,
SignInWithEmailAsync, SignInWithThirdPartyAsync), and ApplySession at
LatticeSocialClient.SignIn.cs:99-103 which calls UseBearerToken(session.AccessToken).
The session object:
public sealed record LatticeSession(
string AccessToken, // JSON: access_token
string RefreshToken, // JSON: refresh_token
int ExpiresInSeconds, // JSON: expires_in
string AccountId); // JSON: account_id
Verified against: control-plane/lattice-social-client/src/Identity.cs:43-47.
The provider enum¶
SignInWithThirdPartyAsync accepts an IdentityProvider; its wire value is the lowercase name.
Verified against: Identity.cs:15-36.
Option B — raw REST from Unity¶
If you don't want the SDK dependency, call the endpoint directly. Any HTTP client works; here's
UnityWebRequest:
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
[System.Serializable] class GuestReq { public string region = "eu"; }
[System.Serializable] class TokenResp { public string access_token; public string refresh_token;
public int expires_in; public string account_id; }
IEnumerator GuestLogin(System.Action<string> onToken)
{
var body = JsonUtility.ToJson(new GuestReq());
using var req = new UnityWebRequest("http://localhost:3005/guest", "POST");
req.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(body));
req.downloadHandler = new DownloadHandlerBuffer();
req.SetRequestHeader("Content-Type", "application/json");
yield return req.SendWebRequest();
if (req.result != UnityWebRequest.Result.Success) { Debug.LogError(req.error); yield break; }
var resp = JsonUtility.FromJson<TokenResp>(req.downloadHandler.text);
onToken(resp.access_token);
}
The email-login variant just posts to /login with { "email": …, "password": … } and reads the
same TokenResp.
Verified against: the request/response shapes in Contracts.cs:4-21 and the handlers in
Program.cs:127-156.
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. The binding'sMatchmakerhelper takes the access token and does that exchange for you — see chapter 04; and - the social service (friends/presence/parties), which the SDK does for you after sign-in.
Verified against: lattice-director/src/LatticeDirector/Program.cs:141-160 (matchmake requires a
valid bearer via PlayerAuthenticator.Authenticate).
Gotchas and honesty notes¶
Third-party sign-in is fail-closed by default
Steam/Epic/Google/etc. ticket verification 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. The in-process test host disables this with
LATTICE_DISABLE_RATE_LIMIT=1.
Verified against: Program.cs:62-88.
Next: 04 — Lobbies & matchmaking, to turn that token into a game server endpoint.