DEPLOY WITH HEADLESS OAUTH
This guide shows you how to deploy swamp serve with OAuth authentication in an
environment where no browser is available — Kubernetes pods, CI runners, or
systemd services.
Prerequisites
- A collective with owner or admin role
swamp auth logincompleted (to create the token)
1. Create a collective API token
Create a token with both oauth:manage and serve:* scopes:
swamp auth token create --collective myorg \
--scopes oauth:manage,serve:* \
--name headless-serveCopy the token immediately — it is shown only once.
oauth:manage allows the server to register itself as an OAuth client.
serve:* allows instance registration and heartbeats.
2. Set the token in your deployment environment
Store the token as SWAMP_API_KEY in your deployment's secret management:
Kubernetes Secret:
kubectl create secret generic swamp-serve \
--from-literal=SWAMP_API_KEY=swamp_org_abc123...Reference it in your pod spec:
env:
- name: SWAMP_API_KEY
valueFrom:
secretKeyRef:
name: swamp-serve
key: SWAMP_API_KEYsystemd:
# /etc/swamp-serve.env
SWAMP_API_KEY=swamp_org_abc123...# In the [Service] section of the unit file
EnvironmentFile=/etc/swamp-serve.envShell (CI or scripts):
export SWAMP_API_KEY=swamp_org_abc123...3. Start the server
swamp serve --auth-mode oauth \
--admins swampadmin \
--allowed-collectives myorgWith SWAMP_API_KEY set, the server registers its OAuth client and resolves
admin usernames without any browser interaction. No verification URL is shown,
no code needs to be entered.
Setting a stable client name
In container and Kubernetes environments, the default client name
(swamp-serve-{repoName}-{hostname}) includes an ephemeral hostname that
changes on every pod restart. Use --oauth-client-name or
SWAMP_OAUTH_CLIENT_NAME to set a stable, deployment-meaningful name:
swamp serve --auth-mode oauth \
--oauth-client-name prod-api-server \
--admins swampadmin \
--allowed-collectives myorgOr via environment variable in a pod spec:
env:
- name: SWAMP_OAUTH_CLIENT_NAME
value: prod-api-server4. Verify the bootstrap succeeded
Check the server logs for these messages in order:
SWAMP_API_KEY verified with oauth:manage scope — registering OAuth client (headless)
Registered OAuth client <clientId> via SWAMP_API_KEY (headless)
Using SWAMP_API_KEY to resolve admin/allowed-user usernames: swampadmin
Resolved admin swampadmin to user:<sub>Confirm the server is ready:
curl -s https://your-server:9090/ready | jq .{ "ready": true, "instanceId": "a1b2c3d4" }Subsequent starts
After the first boot, OAuth client credentials and admin mappings are cached in
the vault. Subsequent starts use the cached values — SWAMP_API_KEY is still
read (for instance registration) but the OAuth registration step is skipped:
No stored OAuth client credentials found — first-time setup requiredThis message appears only on the first boot. On subsequent starts, the server loads credentials from the vault silently.
Key rotation
SWAMP_API_KEY is read fresh from the environment on each boot. To rotate the
key:
- Create a new token with the same scopes
- Update the secret in your deployment environment
- Restart the server
The server picks up the new key on restart. No vault changes or OAuth re-registration is needed — the stored client credentials remain valid.
Troubleshooting
Missing oauth:manage scope:
SWAMP_API_KEY is missing the "oauth:manage" scope required for headless OAuth
client registration. Generate a new collective API token that includes
"oauth:manage".Create a new token with both oauth:manage and serve:* scopes.
Admin username not found:
Failed to resolve admin 'swampadmin': <message>. Ensure the username exists on
https://swamp-club.com.Verify the username in --admins exists on swamp-club. The server resolves
usernames to principal IDs at startup.
Key validation failed:
SWAMP_API_KEY validation failed: <status> <statusText>Check that the token has not been revoked or expired. Verify with
swamp auth whoami.
Related
- Set Up OAuth Authentication — interactive OAuth setup for environments with a browser
- Run as a System Daemon —
run
swamp serveas a launchd or systemd service - Run a Multi-Instance Deployment
— deploy multiple
swamp serveinstances behind a load balancer - Serve Flags — full flag and environment variable reference
- The bootstrap client —
how headless bootstrap works and why it requires
oauth:manage