Skip to content

Sysadmin OAuth Setup

Kurt edited this page Jul 9, 2026 · 2 revisions

OAuth Setup

Audience: Sysadmin Status: ✅ Ready

Configuring OAuth for a production deployment. TelosMUD is OAuth-only (no passwords, no SSH): a player connects, the gate prints a clickable login URL, they authenticate with GitHub in a browser, and the gate picks up the result. This page covers the production wiring — a real domain, secure cookies, a persistent session key, and the gate↔account trust secrets — and contrasts with the local setup in Running Locally. GitHub is the only provider implemented.

If you only want to try OAuth on your workstation, use Running Locally → "Authentication: real OAuth (local)"; this page is for a public server.

The pieces

Production OAuth involves the account service (telos-account) hosting the browser broker at :8080, a GitHub OAuth App on your real domain, Redis (device-auth sessions), and the gate↔account trust secrets that let the gate believe an authenticated session. The broker web server runs only when TELOS_WEB_LISTEN is set and Redis is reachable.

1. Register the GitHub OAuth App (production domain)

Create a GitHub OAuth App pointed at your real, TLS-fronted domain:

  • Homepage URL: https://mud.example.com
  • Authorization callback URL: https://mud.example.com/auth/github/callback

Record the Client ID and generate a Client Secret. (Contrast the local setup, which uses http://localhost:8080 and its /auth/github/callback.)

2. Configure telos-account for production

Set these on the account service:

Variable Production value Notes
TELOS_GITHUB_CLIENT_ID from the OAuth App
TELOS_GITHUB_CLIENT_SECRET from the OAuth App keep it a secret, not in the image
TELOS_WEB_LISTEN :8080 the broker port (put it behind your TLS terminator)
TELOS_WEB_PUBLIC_URL https://mud.example.com the public base URL that appears in the login link and must match the callback domain
TELOS_WEB_SECURE_COOKIES 1 on — the broker is TLS-fronted in prod (dev sets 0 for plain HTTP)
TELOS_WEB_SESSION_KEY a persistent random secret signs the broker's CSRF/PKCE cookies; must be stable across restarts and shared across account replicas, or in-flight logins break
TELOS_REDIS_ADDR your Redis required — device-auth sessions live here; without Redis the broker and device login are disabled

TLS itself belongs on your terminator/ingress in front of :8080; the account service serves plain HTTP behind it, which is exactly why TELOS_WEB_SECURE_COOKIES=1 and a real TELOS_WEB_PUBLIC_URL matter.

3. The gate↔account trust secrets

The account service is off the hot path — the world trusts a signed session assertion rather than calling the account per action — so a real deploy must provision the secrets that make that trust chain sound. These are the real secrets referenced by the fail-closed boot gates in Deployment:

  • The shared caller tokenTELOS_ACCOUNT_CALLER_TOKEN. The account gRPC API (:9100) is reachable only by the gate; the caller token authenticates that the caller is the gate. Set the same value on the account service and the gate. Without it, the account service refuses to boot an open API unless TELOS_ALLOW_INSECURE=1 — which production must not set.
  • The account assertion signing key and the world's matching verify keyTELOS_ACCOUNT_SIGNING_KEY on the account service, TELOS_ACCOUNT_VERIFY_KEY on every world shard. The account service signs the session assertion; the world verifies it offline against that public key and sets a session's trust tier only from a signature-checked claim. Without a verify key, a discoverable world refuses to boot unless TELOS_ALLOW_INSECURE=1.
  • The handoff keypairTELOS_HANDOFF_SIGNING_KEY / TELOS_HANDOFF_VERIFY_KEY on each world. World↔world handoff snapshots are Ed25519-signed (this is what lets an admin/builder keep elevation across a shard walk — see Trust Tier Model); provision the keypair so cross-shard handoff runs on a signed path. Without a verify key, a discoverable world refuses to boot unless TELOS_ALLOW_INSECURE=1.

The rule of thumb from Deployment: production sets no TELOS_ALLOW_INSECURE gate to 1; it supplies the real secrets instead. Setting the insecure flag to paper over a missing secret would run the mesh open to spoofing (the gRPC mesh is plaintext — trust is these app-layer tokens/signatures, so keep the mesh private and the secrets set).

4. Point the gate at the account service

The gate must have TELOS_ACCOUNT_TARGET set to the account service's internal address (e.g. account:9100) and must carry the same TELOS_ACCOUNT_CALLER_TOKEN. A production gate is a release build, so the dev bypass is compiled out; there is nothing to disable. The player-facing transport is TLS telnet (see Deployment → Transports & TLS).

The login flow (what the player sees)

  1. The player connects to the gate over TLS telnet.
  2. The gate mints a short-lived device handle and prints a https://mud.example.com/login/<handle> URL; it then polls for completion.
  3. The player opens the URL; the broker (PKCE + CSRF-protected state) redirects to GitHub, and on approval GitHub calls back to /auth/github/callback.
  4. The broker verifies state, exchanges the code, fetches the GitHub identity, and resolves-or-creates the account by the GitHub identity — never by email.
  5. The gate's poll sees the completed authorization, receives the account id and character list, and runs character select/create.

There is no typed link code and no connect <code> command.

First admin

The very first admin is minted by pinning TELOS_BOOTSTRAP_ADMIN to a GitHub login before that person's first sign-in — see First Admin Setup for the bootstrap pin, the telos-account set-tier break-glass CLI, and promoting further admins.

Troubleshooting

  • Login link points at localhost / callback mismatchTELOS_WEB_PUBLIC_URL isn't set to the public domain, or the GitHub App's callback URL doesn't match it.
  • Cookie/state errors after the redirectTELOS_WEB_SESSION_KEY isn't stable across restarts/replicas, or TELOS_WEB_SECURE_COOKIES=1 without actual TLS in front.
  • Device login "disabled" — Redis is unreachable; the gRPC API still serves, but the broker needs Redis.
  • A service refuses to start with a "refusing to start" error — a required trust secret is missing; supply it (do not set TELOS_ALLOW_INSECURE). See the fail-closed gates in Deployment.

Clone this wiki locally