Skip to main content

API KEY AUTHENTICATION

API keys authenticate CLI commands and programmatic API requests. There are two types: personal keys and collective tokens.

Key formats

Type Prefix Body Example
Personal key swamp_ 64 letters (A–Z, a–z) swamp_aBcDeFgHiJkL...
Collective token swamp_org_ 64 lowercase hex characters (32 bytes) swamp_org_3f9ac1e07b2d...

Authentication headers

API requests accept either header:

x-api-key: swamp_a1b2c3...
Authorization: Bearer swamp_a1b2c3...

The CLI sends Authorization: Bearer when the user is logged in. The x-api-key header remains accepted for backwards compatibility and is still used internally on specific per-call paths (e.g. extension push, yank). When both are present, Authorization takes precedence.

Device identity

In addition to the auth header, the CLI sends Swamp-Distinct-Id on every request to /api/*:

Swamp-Distinct-Id: c2f3eae0-d758-4174-9e8d-7b3f9a000001

The value is a per-device UUID lazy-created and stored by the CLI at ~/.config/swamp/identity.json. It enables stable per-device attribution for telemetry on requests that carry no API key — without it the server falls back to a per-request anon_* hash that changes on every call from the same machine.

The header is untrusted:

  • It never authenticates or authorizes a request.
  • It never resolves to a user record server-side.
  • A session or API key always wins over the header when computing the distinct_id for an event.
  • The server validates the value as a canonical UUID and falls back to the anon_* IP+UA hash on any other input.

Credential storage

The CLI stores credentials in auth.json in the Swamp config directory: $SWAMP_CONFIG_DIR, $SWAMP_HOME/config, $XDG_CONFIG_HOME/swamp, or ~/.config/swamp, the first that applies. File permissions are set to 0o600. Writes are atomic (temporary file, then rename) to prevent corruption.

The stored structure contains:

Field Description
serverUrl Server the key authenticates against
apiKey The raw API key (swamp_ prefix)
apiKeyId Key ID for revocation tracking
username Authenticated username
collectives Cached collective membership slugs
apiKeyFingerprint Fingerprint of the SWAMP_API_KEY value the cached identity belongs to

When SWAMP_API_KEY is set, the CLI caches the identity it resolved in auth.json and keys the cache on apiKeyFingerprint. A different key, or a file written by an older CLI that stored the key's first 12 characters instead, reads as stale and the identity is fetched again.

Verification state

The CLI also keeps the state of its account check in the config directory. Each file has permissions 0o600. swamp auth logout deletes all of them.

File Contents
auth_verified.json The signed proof from swamp-club's last verified answer
auth_fail_open.json When swamp-club began returning server errors, if it is
auth_token_check.json When the SWAMP_SIGNIN_TOKEN key was last checked live
auth_refresh_attempt.json When the CLI last tried to refresh auth_verified.json

Credential precedence

  1. --club-api-key-file (swamp serve, swamp serve check-config and swamp serve daemon enable only)
  2. SWAMP_API_KEY_FILE environment variable
  3. SWAMP_API_KEY environment variable
  4. auth.json in the Swamp config directory

SWAMP_API_KEY_FILE and SWAMP_API_KEY are mutually exclusive: with both set and no --club-api-key-file, every command fails with SWAMP_API_KEY and SWAMP_API_KEY_FILE are mutually exclusive — unset one of them. A key file is read on every command and trimmed of whitespace; a missing, unreadable or empty file is an error.

The server is SWAMP_CLUB_URL if set, otherwise the serverUrl in auth.json, otherwise https://swamp-club.com.

When a collective key is set from any of the first three sources, swamp auth login and swamp auth logout are disabled.

Environment variables

Variable Purpose
SWAMP_API_KEY API key for authentication (overrides auth.json)
SWAMP_API_KEY_FILE Path to a file holding the API key; mutually exclusive with SWAMP_API_KEY
SWAMP_SIGNIN_TOKEN Signin token issued with the collective token in SWAMP_API_KEY
SWAMP_CLUB_URL Server URL override
SWAMP_CONFIG_DIR Directory holding auth.json and the verification state

SWAMP_SIGNIN_TOKEN is used only when it was issued for the active API key; a signin token for any other key is ignored. It has no file variant.

Scope

Personal keys create a full user session. The authenticated user's identity, roles, and collective memberships are all available. Most CLI commands that require authentication work with personal keys.

Collective tokens create a collective context only. They do not create a user session. The middleware sets collectiveTokenContext with the collective ID, slug, and token ID. Actions performed with a collective token are attributed to the collective, not to any individual user. Some commands — such as swamp extension push — accept collective tokens for CI/CD use cases where no individual operative is involved.

Personal keys grant access to all collectives the user belongs to. Collective tokens are scoped to a single collective.

Collective token scopes

Scope Grants access to
extensions:push Push extensions on behalf of the collective
extensions:promote Promote extension versions
extensions:read Read extension metadata
extensions:* All extension operations
lab:read Read lab issues
lab:write Create and update lab issues
lab:* All lab operations
profile:read Read operative profiles
profile:write Update operative profiles
profile:* All profile operations
collective:read Read collective metadata
collective:write Update collective settings
collective:* All collective operations
billing:manage Manage billing and subscriptions
feed:write Submit feed posts
notifications:read Read notifications
notifications:write Mark notifications as read
notifications:* All notification operations
oauth:manage Manage OAuth applications and consents. When set on SWAMP_API_KEY, enables headless OAuth client registration for swamp serve --auth-mode oauth — no browser interaction needed on first boot. See Deploy with Headless OAuth
serve:* Start swamp serve with --auth-mode token or --auth-mode oauth
datastore:* Set up external datastores (S3, GCS, extension-provided backends)
vault:* Create and manage non-local vault configurations

A personal key carries all scopes implicitly. A collective token must include the required scope explicitly; without it the server returns HTTP 403.

Role requirements

Operation Required role
Create personal key Any authenticated user
Create collective token Owner or admin
Revoke collective token Owner or admin
Delete collective token Owner or admin

Limits

Each collective can have a maximum of 25 API tokens.

Expiration

Collective tokens support an optional expiration date set at creation time. Expiration is enforced at verification — an expired token is rejected even if it is still enabled.

A personal key minted by swamp auth login expires 90 days after creation; logging in again mints a fresh one. Keys minted before this limit keep no expiry. Personal keys created from the web UI do not expire.

Key lifecycle

  1. Created — key is generated, raw value shown once, hash stored
  2. Enabled — key authenticates requests normally
  3. Revoked — key is disabled and can no longer authenticate; remains visible in the UI
  4. Deleted — key is permanently removed

Revoked keys cannot be re-enabled.

Security

Keys are hashed with SHA-256 (base64url encoding) before storage. The raw key is returned only at creation time. The full hash is never exposed in API responses or the web UI.

Fingerprints

A key's fingerprint is the first 16 characters of the lowercase hex SHA-256 of the full key. It names a key without revealing it and cannot be used to authenticate. The same value appears in:

  • the Fingerprint column of the Access Tokens panel on /u/<username>
  • the Fingerprint column of a collective's token list in its settings
  • swamp auth whoami, swamp auth token create and swamp auth token list
  • the fingerprint field of the collective token API responses

To match a key you hold to its row, see Identify a key.

API endpoints

Personal keys (BetterAuth)

Method Endpoint Description
POST /api/auth/api-key/create Create a key
GET /api/auth/api-key/list List keys
POST /api/auth/api-key/update Update a key
POST /api/auth/api-key/delete Delete a key

These endpoints require an active session (cookie or session token).

A personal key can also revoke itself, which is how a CLI discards its own credential:

Method Endpoint Description
DELETE /api/v1/me/api-key Delete the presenting key

It authenticates with the key being deleted (x-api-key or Authorization: Bearer) and takes no body — the key id comes from the credential, so a key can only delete itself. It answers 200 {"revoked": true, "id": "<keyId>"}, 403 for a collective token or a browser session, and 401 for a key that no longer exists. Another replica may keep accepting a revoked key for up to 60 seconds.

Collective tokens

Method Endpoint Description
GET /api/v1/collectives/{slug}/api-tokens List tokens
POST /api/v1/collectives/{slug}/api-tokens Create a token
PATCH /api/v1/collectives/{slug}/api-tokens/{tokenId} Revoke a token
DELETE /api/v1/collectives/{slug}/api-tokens/{tokenId} Delete a token

These endpoints require an active session with owner or admin role on the collective. List and create responses carry each token's keyPrefix and its fingerprint as fingerprint. The create response also carries signinToken unless the server could not sign one; it is never returned again.

Collective management

The collective:read and collective:write scopes are honoured by the collective REST API — reading a collective, its members, its pending invitations, and its published extensions, plus updating its settings. See Collective API for the endpoint table, and /api/v1/openapi.json for the machine-readable description.

Membership writes (invite, remove, change role) accept a session only and cannot be driven by any bearer credential; the reason is on that page.

CLI Commands

swamp auth login

Authenticate with a Swamp server.

Flag Description
--server Server URL (env: SWAMP_CLUB_URL)
--username Username or email
--password Password (omit to prompt)
--no-browser Disable browser login, use username/password instead

Default behavior opens a browser for device-flow authentication.

swamp auth logout

Remove stored authentication credentials. No flags.

swamp auth whoami

Show current authenticated identity. Aliased as swamp auth status. No flags. Use --json for structured output.

Personal key output:

stack72 (paul@swamp-club.com) on https://swamp-club.com
Fingerprint: 3afc78556734e019
Plan: Team
Collectives:
  swamp              Team  active
  system-initiative  Free
  stack72            Free  trial: 13 days left (ends 2026-08-19)

Plan is a roll-up: the strongest plan across every collective you belong to. It answers "am I paying for anything?" but not "which collective needs upgrading?" — that is what the per-collective list is for. Billing attaches to a collective, never to a user, so a private extension push is refused on the namespace's plan, not on yours.

The third column shows the collective's billing status when it is paying, and its trial when it is not. Three details worth knowing:

  • Billing status is shown to owners and admins only. Plain members see the plan and its name but not the raw status, matching the access rules on the collective's billing page. When triaging a report from a member, expect the field to be missing rather than null.
  • A paying collective never shows a trial, even if its 30-day clock is still running. In --json its trial is null.
  • The trial grants no entitlement. Reaching day 31 changes what you are told, not what you can do.

Fingerprint is the fingerprint of the key in use, whether it comes from auth.json or SWAMP_API_KEY. --json carries it as fingerprint. The key id is not shown.

If the server sends no entitlement — a self-hosted or older swamp-club — whoami falls back to the single Collectives: a, b, c line.

Collective token output:

Collective token: myorg on https://swamp-club.com
Scopes: extensions:push, extensions:read
Fingerprint: a40f6d9d7459f9aa
Collectives: myorg

Collective token JSON output (--json):

{
  "authenticated": true,
  "serverUrl": "https://swamp-club.com",
  "collectiveToken": true,
  "collectiveSlug": "myorg",
  "scopes": ["extensions:push", "extensions:read"],
  "fingerprint": "a40f6d9d7459f9aa",
  "collectives": ["myorg"]
}

The collective token response omits the id, username, email, and name fields that appear in the personal key response.

swamp auth token create

Create a scoped API token for a collective from the CLI.

Flag Description
--collective <slug> Collective to create the token for (required)
--scopes <comma-separated> Scopes to grant, e.g. extensions:push,serve:* (required)
--name <label> Token label; defaults to cli-<hostname>-<timestamp> (optional)
--json Output in JSON format

Requires personal authentication (swamp auth login) — collective tokens cannot create other tokens. Only collective owners and admins can create tokens.

The token key is shown once at creation time and cannot be retrieved later. A Fingerprint: line above it gives the token's fingerprint, computed locally from the new key; --json carries it as fingerprint. Maximum 25 tokens per collective.

When swamp-club issues a signin token with the new key, it is printed below the key under Signin token:, and --json carries it as signinToken. It is shown once and cannot be retrieved later. Set it as SWAMP_SIGNIN_TOKEN beside SWAMP_API_KEY.

swamp auth token list

List all API tokens for a collective.

Flag Description
--collective <slug> Collective to list tokens for (required)
--json Output in JSON format

Requires personal authentication (swamp auth login). Only collective owners and admins can list tokens.

The table output shows each token's name, id, fingerprint, scopes, creation date, and last-used date. Against a server that does not report fingerprints, the key prefix appears in the fingerprint's place. JSON output includes id, keyPrefix and fingerprint for each token. A token disabled with Revoke in the web UI appears with enabled: false in JSON output.

swamp auth token revoke

Permanently remove an API token from a collective. The token disappears from swamp auth token list and its key stops working. To disable a token and keep it listed, use Revoke in the collective's settings in the web UI.

Argument Description
<token-id> UUID of the token to revoke
Flag Description
--collective <slug> Collective the token belongs to (required)
--json Output in JSON format

Requires personal authentication (swamp auth login). Only collective owners and admins can revoke tokens. A removed token cannot be restored.

Use swamp auth token list --collective <slug> to find the token id.

swamp auth server-login

Store a server token for a swamp serve instance — subsequent --server commands use it automatically.

Flag Description
--server Server URL to associate the token with (required unless SWAMP_SERVE_URL is set)
--token Server token in <name>.<secret> format (required for token auth; omit for OAuth/device flow)

CLI commands with key-type requirements

Every CLI command needs a credential except those listed in Swamp Account Requirement. The commands below additionally require a particular key type, or a scope when run with a collective token.

Command Key type
swamp auth whoami Personal or Collective
swamp auth token create Personal
swamp auth token list Personal
swamp auth token revoke Personal
swamp extension push Personal or Collective
swamp extension yank Personal
swamp extension unyank Personal
swamp extension deprecate Personal
swamp extension undeprecate Personal
swamp issue submit Personal
swamp issue ripple Personal
swamp issue get Personal
swamp datastore setup extension Personal or Collective (datastore:*)
swamp vault create <type> Personal or Collective (vault:*); local_encryption needs no scope
swamp serve --auth-mode token Personal or Collective (serve:*)
swamp serve --auth-mode oauth Personal or Collective (serve:*)

When a collective token is used with a command that requires a specific scope, the server returns HTTP 403 with:

{ "error": "This token requires the <scope> scope" }