Skip to main content
← Back to list
01Issue
FeatureTriagedSwamp CLIPublic
Assigneesstack72

Relationships

#1649 feat(serve): headless OAuth client bootstrap via SWAMP_API_KEY

Opened by stack72 · 8/14/2026

Problem

swamp-serve's OAuth mode requires a manual device-grant approval in a browser for first-time setup. This blocks deployment in Kubernetes pods, autoscaling groups, and unattended installs where no human is present at boot time.

PR #2141 added SWAMP_API_KEY support for instance registration and heartbeats, but the OAuth client registration (the client_id + client_secret that powers user auth) still requires the device-grant browser flow.

Proposed Solution

Extend SWAMP_API_KEY (collective API token with serve:* scope) to also handle OAuth client registration and admin username resolution — making the entire bootstrap fully headless.

The swamp-club side has already shipped — POST /api/auth/oauth2/register and GET /api/auth/resolve-user now accept collective tokens with serve:* scope.

Changes needed in swamp CLI

  1. Add registerClientWithApiKey() in src/serve/oauth_registration.ts — calls POST {providerUrl}/api/auth/oauth2/register with SWAMP_API_KEY as bearer auth, returns client_id + client_secret

  2. Wire SWAMP_API_KEY into the OAuth bootstrap decision tree in src/cli/commands/serve.ts — when SWAMP_API_KEY is set and no stored OAuth client credentials exist, use registerClientWithApiKey() instead of the device-grant flow in the registerClient callback passed to resolveOAuthClientCredentials()

  3. Use SWAMP_API_KEY for admin username resolution — when SWAMP_API_KEY is available and admin resolution is needed (resolveUsername() calls), use it as the bearer token instead of requiring a second device grant. The resolveUsername function already accepts any bearer token.

  4. Move SWAMP_API_KEY env var read earlier in serve.ts — currently read at ~line 2150 (after the OAuth bootstrap block). Move to before the resolveOAuthClientCredentials() call so it's available for both client registration and admin resolution. The existing instance registration and heartbeat code continues to use the same variable.

Boot flow after this change

SWAMP_API_KEY set?
├─ No  → existing device-grant flow (unchanged)
└─ Yes → stored OAuth client credentials in vault?
         ├─ Yes → use stored credentials (unchanged)
         └─ No  → POST /api/auth/oauth2/register with SWAMP_API_KEY
                   → store client_id + client_secret in vault
                   → resolve admin usernames via SWAMP_API_KEY
                   → register instance (already works via #2141)
                   → start heartbeats (already works via #2141)
                   → server ready, zero browser interaction

What does NOT change

  • User auth flow (device grant for end users connecting to serve)
  • --auth-mode token behavior
  • Device-grant bootstrap when SWAMP_API_KEY is not set
  • Instance registration + heartbeats (#2141)
  • No new CLI flags, env vars, or config options
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNEDCLASSIFICATION

Triaged

8/14/2026, 11:55:41 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack728/14/2026, 11:53:13 PM

Sign in to post a ripple.