Relationships
#1390 Purely local operations require a swamp-club account: local-token serve is gated while deprecated --auth-mode none is not, third-party OIDC is gated, and 'Local_Encryption' is paywalled by capitalization
Opened by magistr · 7/24/2026
Summary
Several gated operations perform no swamp-club.com interaction whatsoever, yet refuse to run without a swamp-club account. The most consequential is swamp serve --auth-mode token, whose token validation is entirely local. Because the two authenticated modes are gated and --auth-mode none is not, an account-less user is pushed onto the deprecated, unauthenticated mode — the security gradient runs backwards.
The operations are genuinely local
src/serve/token_auth.ts— the imports arerepository_factory,libswamp/mod,server_token_model,deps,logger. No HTTP client, no swamp-club call. Incoming tokens are redeemed against the localswamp/server-tokenmodel, with the secret in the local vault (server_token_model.ts:151-176).src/libswamp/vaults/create.ts— writes a local YAML config. Secrets go to the user's own provider.src/libswamp/datastores/setup.ts— writes local config and syncs to the user's own bucket with the user's own cloud credentials.
None of these contacts swamp-club at any point, so the gates are pure client-side pre-flights.
Deterministic repro
A — purely local serve is blocked
export SWAMP_HOME="$(mktemp -d)"; mkdir -p "$SWAMP_HOME/config" # no credentials
swamp serve --host <loopback> --port 39118 --auth-mode token --admins user:alice --no-scheduleObserved:
Error: swamp serve is a team feature that requires a free swamp-club.com account.
...
Your token should include the serve:* scope.Loopback bind, local token auth, no swamp-club feature in play. On an air-gapped host this cannot be satisfied at all.
B — the only mode that runs is the deprecated one
serve.ts:960-963 gates mode === "oauth" || mode === "token". --auth-mode none is ungated, and serve.ts:965-971 then warns that it "is deprecated and will be removed in a future release. Use --auth-mode token" — the mode just refused. assertOffLoopbackSecurity (serve.ts:181-198) additionally forbids none off-loopback, so an account-less user cannot bind to a LAN address in any mode.
C — a case variant of a local vault type is paywalled
swamp vault create Local_Encryption my-vault # -> paywall
swamp vault create local_encryption my-vault # -> created fine, fully offlinevault_create.ts:85 compares vaultType !== "local_encryption" case-sensitively, while the registry normalizes with toLowerCase() throughout (vault_type_registry.ts:90,97,127,...). So the same offline AES-GCM file vault is gated or not depending on capitalization.
D — third-party OIDC still requires a swamp-club account
--oauth-provider <url> accepts any HTTPS issuer (serve_auth_config.ts:119-135), but the gate at serve.ts:960 fires on mode === "oauth" unconditionally. swamp serve --auth-mode oauth --oauth-provider https://[HOST-1] --admins alice involves swamp-club nowhere and is still refused.
Impact
The practical effect of gating token and oauth while leaving none open is that the least secure configuration is the one available by default to anyone not signed in. A user who just wants an authenticated local server — the thing the deprecation warning explicitly tells them to use — has to create an account to get it, and if they do not, the tool steers them to the mode it is simultaneously warning them off.
Independently: local vault creation, local datastore setup, and local serve are the features people reach for before they have decided whether to join swamp-club at all. Requiring the account for operations that never contact the service makes the requirement look like a paywall on local functionality rather than an authorization check.
Expected
Some of this may be deliberate product policy rather than a defect, so treating it as one question: which of these gates are intended?
- If
serve --auth-mode tokenis meant to be gated, the deprecation warning on--auth-mode noneshould not recommend a mode the user cannot use, and the gate message should say so up front. --auth-mode oauthwith a non-swamp-club issuer has no swamp-club dependency and looks like it should be ungated.- The
Local_Encryptioncapitalization gap is unambiguously a bug — compare case-insensitively, as the registry does. - Whatever the policy, it is currently documented nowhere: not in
--auth-modehelp, not in thevault create/datastore setuphelp or examples, not in the README, and not in the shipped skills that walk users through exactly these commands (share/guide.md:95-99,vault/references/providers.md,repo/reference.md:234,310). Users meet the requirement for the first time at runtime, mid-task.
Environment
- Verified against source
main@10943ef. Gate shipped ina519305(#1934), 2026-07-23; installed stable20260722.210030.0-sha.7ff1e2f0predates it, so none of this reproduces on the current release binary yet. - macOS 14.
Closed
No activity in this phase yet.
magistr commented 7/24/2026, 9:57:32 PM
Correction from the author — please read before triaging. I got a load-bearing claim wrong.
My 'Expected' section asserted the account requirement is 'documented nowhere'. That is false, and I should have checked the published manual before writing it. I only checked the source tree for docs/ and manual/ directories, found none, and generalised from that. The manual at /manual documents both the requirement and its reasoning:
- /manual/explanation/api-key-scoping: 'Some features — external datastores, non-local vaults, and swamp serve in token or oauth mode — require a swamp-club.com account even though the resources they manage live locally or in your own cloud infrastructure.'
- Same page, the rationale: 'these features cross the boundary from single-machine use into shared team state... an S3 datastore, an AWS Secrets Manager vault, or a network-accessible serve instance affect resources that multiple team members rely on — and Swamp needs to know who is configuring them.'
- /manual/how-to/authenticate-with-api-keys covers the collective-token path for the same three features.
So the gating is deliberate, documented policy with a stated rationale, not an oversight. My framing of sections A, B and D as defects was wrong, and the question I posed ('which of these gates are intended?') is already answered in the manual. Apologies for the noise.
What I still think stands, narrowed:
Section C is a real bug and unaffected by the above.
vault create Local_Encryptionis gated whilelocal_encryptionis not, because vault_create.ts:85 compares case-sensitively against a registry that normalises with toLowerCase(). A local AES-GCM file vault should not be gated on capitalisation. If nothing else here is actionable, this is.Discoverability, restated correctly. The requirement is in the manual but not at the point of use: not in
--auth-modehelp, not invault create/datastore setuphelp or examples. The user meets it as a runtime error. That is a much weaker claim than the one I filed and may not be worth acting on.The deprecation-warning contradiction. serve.ts:965-971 tells an account-less user to 'Use --auth-mode token' — the mode the gate just refused. Whatever the policy, that specific sentence points at a door the reader cannot open, and could name the account requirement instead.
Feel free to close as intended-behaviour if only point 1 is worth keeping; I would not object to it being split out and the rest dropped.
Sign in to post a ripple.