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

Relationships

#890 swamp serve --auth-mode token: redeem reads token-main as null → every valid token rejected 'Authentication failed' (real error hidden at debug)

Opened by magistr · 6/29/2026· Shipped 6/29/2026

Summary

swamp serve --auth-mode token rejects every freshly-minted, active server token with WebSocket auth rejected: "Authentication failed". The real (debug-only) error is Server token '<name>' does not exist — mint it first: serve's redeem path reads the token's token-main data artifact and gets null, even though the token was just minted and is visible via swamp access token list / swamp model get. --auth-mode none works perfectly, so the entire client→serve→model→datastore→vault chain is fine — only token validation is broken.

Environment

  • swamp 20260629.145610.0-sha.ac2f277d (stable), client and server on the same version.
  • Reproduces on both filesystem and @keeb/mongodb-datastore datastores.
  • macOS client + Linux (debian-slim) serve container; also reproduces serve+client both local on macOS.

Minimal repro (no container, no proxy, no TLS)

# terminal 1
swamp serve --host 127.0.0.1 --port 9099 --auth-mode token --admins user:magistr --log --log-level debug

# terminal 2
TOK=$(swamp access token mint t --principal user:magistr --duration 1d --vault <any-vault> --json \
      | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])')
swamp auth server-login --server ws://127.0.0.1:9099 --token "$TOK"
swamp model method run <model> <method> --server ws://127.0.0.1:9099

Client prints {"error":"Could not connect to ws://127.0.0.1:9099/"}. Serve (debug) logs:

DBG serve·token-auth Token authentication failed for "t": "Server token 't' does not exist — mint it first"
WRN serve WebSocket auth rejected from "127.0.0.1": "Authentication failed"

Root cause

serve validates by running the server-token model's redeem method as an ad-hoc run keyed by type + definition name:

src/serve/token_auth.ts:79

modelMethodRun(libCtx, deps, {
  modelIdOrName: split.name,
  methodName: "redeem",
  typeArg: SERVER_TOKEN_MODEL_TYPE.normalized,   // swamp/server-token
  definitionName: split.name,
  inputs: { presentedToken: presented },
})

redeemreadToken() in src/domain/models/access/server_token_model.ts:65:

const raw = await context.readResource!("token-main");   // returns null
if (raw === null) throw new Error(`Server token '${name}' does not exist — mint it first`);

context.readResource("token-main") returns null, so redeem throws "does not exist". mint (writeResource("token","token-main",…)) persists the artifact under the minted instance, but the redeem path's instance-scoped readResource resolves a different owner (the ad-hoc typeArg+definitionName run) and can't see it.

Proof the token exists but serve can't read its data

For a token preboot minted before serve even started:

Check Result
swamp access token mint preboot … created
swamp model get preboot instance exists (id 01f323a8…, type swamp/server-token)
swamp access token list preboot active, full metadata
swamp vault read-secret <vault> server-token-preboot correct 64-char secret (matches the minted secret byte-for-byte)
swamp data list preboot "Model not found"
serve redeemreadResource("token-main") null → "does not exist"

swamp access token list uses a different read path than redeem's instance-scoped readResource, which is why the list sees the token but redeem does not. The swamp data list <name> → "Model not found" (while swamp model get <name> succeeds) corroborates that the instance's data artifact isn't resolvable by the instance.

Independent of

datastore backend (filesystem AND mongo), bind address (localhost / 127.0.0.1 / LAN IP with TLS), transport (ws and wss), mint-before-vs-after serve start, and credential delivery (--token flag and swamp auth server-login). All fail identically. --auth-mode none succeeds in every case.

Secondary issue (observability)

The real error is logged only at debug; serve returns a generic "Authentication failed" and the client surfaces only "Could not connect". This made a config-looking failure extremely hard to diagnose. Suggest logging the redeem failure reason at warn (or distinguishing "token not found" vs "secret mismatch" vs "revoked/expired") so operators can tell a genuine bad token from this internal lookup failure.

Related to the reverse-proxy friction in #889 (WS host allowlist), but this is a separate, more fundamental blocker: even with the host check satisfied and TLS working, token auth never succeeds.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 3 MOREFINDINGS+ 4 MOREPR_MERGED+ 1 MORECONTRIBUTOR_NOTIFIED

Shipped

6/29/2026, 11:26:02 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack726/29/2026, 10:14:28 PM
Editable. Press Enter to edit.

stack72 commented 6/29/2026, 11:26:12 PM

Thanks @magistr for reporting this! The fix has been merged and a release is on its way. We appreciate your contribution to swamp.

Sign in to post a ripple.