Skip to content

Control Plane

The control plane is a small set of .NET 8 services that handle everything around the real-time netcode: identity, matchmaking/fleet orchestration, social, the developer console, and analytics. They are independently deployable and talk to each other over HTTP, sharing one primitive: EdDSA / Ed25519 JWTs verified offline against each issuer's JWKS.

flowchart LR
  subgraph clients[Game clients]
    C[player client]
  end
  subgraph cp[Control plane .NET 8]
    AU[lattice-auth<br/>identity + tokens]
    DI[lattice-director<br/>matchmaking + fleet]
    SO[lattice-social<br/>friends/presence/parties + WS]
    CO[lattice-console<br/>dev/game registry + RBAC :3004]
    AN[lattice-analytics<br/>events + metrics :3006]
    PO[lattice-portal<br/>developer dashboard :3007]
  end
  subgraph dp[Data plane]
    GS[lattice-gameserver]
  end
  C -->|guest/login| AU
  C -->|matchmake/resolve| DI
  C -->|friends/presence| SO
  DI -->|verify access token| AU
  DI -->|mints session token| GS
  GS -->|register/heartbeat| DI
  SO -->|verify JWT / resolve game key| AU
  SO -->|tenancy| CO
  AN -->|validate game key| CO
  PO -->|upstreams| CO
  PO -->|upstreams| AN

Services at a glance

Service Purpose Port Primary auth
lattice-auth Account/identity, Ed25519 token issuance, bans default binding (3004–3010 range) anonymous → bearer JWT
lattice-director Fleet registry, matchmaking, session-token mint default binding bearer JWT (players) + X-Fleet-Token (servers)
lattice-social Friends, presence, parties, invites, chat + WebSocket LB-fronted wss://…:9443/v1/ws bearer JWT or X-Api-Key
lattice-console Developer accounts, game registration + API keys, module admission, RBAC/tenancy authority 3004 developer bearer + game API key
lattice-analytics Telemetry ingestion + RBAC-scoped metrics 3006 game API key (ingest) + developer bearer (query)
lattice-portal The developer dashboard UI 3007 developer session (upstreams console + analytics)

Two non-interchangeable token families

sequenceDiagram
  participant C as Client
  participant AU as lattice-auth
  participant DI as lattice-director
  participant GS as Game server
  C->>AU: POST /guest or /login
  AU-->>C: access_token (iss=lattice-auth, aud=lattice, TTL 10m) + refresh (30d)
  C->>DI: POST /matchmake (Bearer access_token)
  DI->>AU: verify offline via JWKS
  DI-->>C: session_handle
  C->>DI: POST /resolve
  DI-->>C: session_token (iss=lattice-director, aud=lattice-gameserver, TTL 2m) + endpoint
  C->>GS: connect(endpoint, session_token)
  GS->>DI: verify offline via JWKS
  • Access tokensiss=lattice-auth, aud=lattice, alg=EdDSA, TTL 10 min; refresh TTL 30 days. Claims: sub, sid, platform, roles[], region, iss, aud, iat, exp, jti.
  • Session tokensiss=lattice-director, aud=lattice-gameserver, alg=EdDSA, TTL 2 min. Claims: sid, hdl, ep, sub, region, iat, exp, jti.

Both are verified offline against /.well-known/jwks.json published by their issuer. kid in the header selects the public key.

Header conventions

Header Used by
Authorization: Bearer <jwt> everywhere (access token / developer session)
X-Lattice-Api-Key + X-Lattice-Api-Secret game API key — console + analytics + tenancy
X-Fleet-Token director fleet endpoints (shared secret, constant-time compared)
X-Api-Key + X-User-Id (+ X-User-Handle) social server-to-server (impersonation)
X-Lattice-Game-Key / X-Lattice-Game-Secret social / analytics tenancy (cross-game visibility)