Skip to main content
← Back to list
01Issue
FeatureShippedSwamp CLI
Assigneesstack72

Relationships

#1264 CLI support for collective API tokens (phase 3 of #960)

Opened by stack72 · 7/18/2026· Shipped 7/18/2026

Context

Phase 3 of #960. The web side is complete — collective tokens have scopes (phases 1/2), enforcement is live, and whoami surfaces scopes. But the swamp CLI cannot use collective tokens at all. Setting `SWAMP_API_KEY=[REDACTED-SECRET] fails because the CLI's client-side validation doesn't handle the collective token response shape.

Users can already create collective tokens in the web UI at /o/[slug]/settings. After this phase, those tokens work with the CLI for the first time.

Problem

The CLI assumes every API key resolves to a user session. When `SWAMP_API_KEY=[REDACTED-SECRET] is set:

  1. whoami parsing breaks — the CLI expects a user-shaped response (id, username, email, name) but the collective token whoami response has collectiveToken: true, collectiveId, collectiveSlug, scopes, and organizations. The CLI's WhoamiResponse type and getCollectives() extraction don't handle this shape.

  2. Push namespace validation breaksextensionPushPrepare() calls whoami to get the user's collectives, then validates the extension's @collective/ namespace against them. With a collective token, the identity IS the collective — the validation logic needs to recognize this.

  3. 403 errors are generic — when scope enforcement returns "This token requires the extensions:push scope", the CLI shows a generic permission denied. The scope-specific message should surface to the user.

What to change

1. Whoami response handling

Update the CLI's whoami response parsing (src/libswamp/auth/whoami.ts and src/presentation/renderers/auth_whoami.ts) to handle the collective token response shape:

  • Detect collectiveToken: true in the response
  • Extract collectiveSlug, collectiveId, and scopes from the response
  • swamp auth whoami displays: collective identity, slug, and granted scopes
  • JSON mode includes scopes in the output

2. Push namespace validation

Update extensionPushPrepare() (src/libswamp/extensions/push.ts) to handle collective token identity:

  • When whoami returns a collective token response, the collective slug IS the namespace
  • Skip the "does this user belong to this collective" check — the token IS the collective's credential
  • Validate that the extension's namespace matches the token's collective slug

3. Scope-aware error messages

Update ExtensionApiClient.checkResponse() (src/infrastructure/http/extension_api_client.ts) to surface scope-specific 403 messages:

  • Parse the JSON error body from 403 responses
  • If the message matches the scope pattern ("This token requires the X scope"), display it clearly
  • E.g. Error: token lacks required scope 'extensions:push' — create a new token with this scope at https://swamp-club.com/o/<slug>/settings

4. Auth credential handling

Verify that loadIdentity() (src/cli/load_identity.ts) works with `SWAMP_API_KEY=[REDACTED-SECRET]

  • The ClientIdentity sets Authorization: Bearer <apiKey> — this should work since the server resolves both prefixes
  • Ensure mergeIdentityHeaders() and authHeaders() pass the key through without prefix filtering

What this does NOT change

  • No changes to the swamp-club web app
  • No token creation via CLI — tokens are created in the web UI
  • No changes to swamp serve token system (separate auth path)
  • No changes to swamp auth login (still creates personal keys only)

Testing

  • Manual: set SWAMP_API_KEY=[REDACTED-SECRET] with an existing collective token, run swamp auth whoami, run swamp extension push`
  • Unit: whoami response parsing for both user and collective token shapes
  • Unit: push namespace validation with collective token identity
  • Unit: 403 error message parsing for scope-specific errors

Verification

  • swamp auth whoami with a collective token shows collective identity and scopes
  • swamp extension push with a collective token succeeds for the collective's namespace
  • swamp extension push with a scoped token lacking extensions:push shows a clear scope error
  • All existing personal key flows continue to work unchanged
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 4 MOREPR_MERGED+ 1 MORENOTIFICATION_SKIPPED

Shipped

7/18/2026, 11:35:07 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack727/18/2026, 10:12:46 PM

Sign in to post a ripple.