Skip to content

Auth

The agent’s /api/* and /ws/* routes are guarded by an operator gate. The gate is fail-safe: it is enabled only when a GitHub OAuth client id/secret and a master key are configured. Otherwise the agent behaves as before (open) and logs a one-time warning.

The gate is on when all of these are true:

  • auth_github_client_id is set (config).
  • STEELFRAME_GITHUB_CLIENT_SECRET is set (environment).
  • STEELFRAME_MASTER_KEY is set (environment).
  • auth_enabled is not false/0.

Access rule: the GitHub login must be in auth_allowed_users (comma/newline separated config) or be a member of auth_github_org (config, default chipcolate).

These are always mounted; login reports 404 when auth is not configured.

MethodPathPurpose
GET/api/auth/loginRedirect to GitHub OAuth
GET/api/auth/callbackExchange the code, issue a session
GET/api/auth/logoutClear the session cookie
GET/api/auth/meReturn the verified login or 401

Sign in with GitHub. The callback sets a signed sf_session cookie:

HttpOnly; Secure; SameSite=Lax; Max-Age=14 days

The session token is self-contained: v1.<user-b64url>.<expiry-unix>.<HMAC-SHA256>, signed with the master key. There is no server-side session store. The OAuth state carries a nonce and the redirect target in a short-lived cookie, and redirect targets are restricted to same-origin paths.

Every request is verified from the cookie (or an Authorization: Bearer). On success the middleware overwrites X-Auth-User with the verified login, so handlers and audit logs cannot see a spoofed identity.

Desktop has no cookie session to recover in-app. The re-authentication gate opens:

<agent>/api/auth/login?desktop=1&rd=/

The callback renders the session token in the browser as a page for copy-paste. Paste it into the app, which sends it as Authorization: Bearer and saves it to the project registry (projects.toml).

The TUI reads each project’s token from ~/.config/steelframe/projects.toml and sends it as Authorization: Bearer. It also sends X-Auth-User on every request so GitHub issue footers name the real operator.

The agent also accepts a pre-shared automation token from STEELFRAME_TUI_TOKEN. When it matches, the request authenticates as the STEELFRAME_OPERATOR value (or automation).

Create a remote token on the host:

Terminal window
ssh root@HOST cat /root/steelframe-tui.token > /tmp/steelframe-tui.token
steelframe config \
--name makolate-stack \
--url https://makolate.steelframe.chipcolate.com \
--token-file /tmp/steelframe-tui.token \
--operator your-github-login

Resolution order for the operator identity when auth is disabled:

  1. X-Auth-User
  2. X-Forwarded-User
  3. STEELFRAME_OPERATOR
  4. unknown

When auth is enabled, only the verified login survives; client-supplied identity headers are replaced.

STEELFRAME_MASTER_KEY is the HMAC key for session tokens and the source for credential encryption. Keep the same value for the life of the VM; rotating it invalidates sessions and makes existing credentials undecryptable.

  • When the gate is disabled, an unauthenticated request succeeds and the actor is unknown. Set the identity headers or auth to get correct issue footers.
  • 401 responses carry { "error": "unauthenticated", "login_url": "/api/auth/login" }.
  • Session tokens expire after 14 days; the Desktop app prompts for a fresh paste when an agent rejects the saved token.
  • The agent-native OAuth App callback is https://<HOST>/api/auth/callback. The infra oauth2-proxy path uses a separate GitHub OAuth App with callback https://<HOST>/oauth2/callback (see infra/secrets.mk.example).