Relationships
#1384 Collective-token scope cache never expires, is never refreshed by whoami, and cannot be cleared via the CLI — scope changes and revocations never take effect
Opened by magistr · 7/24/2026
Summary
Once a collective token's scopes are cached, they are used forever and there is no supported way to refresh or remove them:
scope_cache.jsonhas no TTL, no timestamp, and no version field. On a cache hit the livewhoamiis skipped entirely.- Changing a token's scopes on swamp-club.com without rotating the token therefore never takes effect on any machine that has already run once.
swamp auth whoamireads scopes live from the server and never writes the cache, so it cheerfully reports scopes that contradict what the gate is enforcing one line later.swamp auth logout— the only command that removes the file — refuses to run whileSWAMP_API_KEYis set, and early-returns when noauth.jsonexists. For a collective-token-only user (CI, headless), both conditions hold, so the file is unreachable through the CLI.
Where (source)
src/infrastructure/persistence/auth_repository.ts:186-214—saveScopeCachewrites{fingerprint, scopes};loadScopeCachevalidates onfingerprintalone. No expiry anywhere.src/cli/mod.ts:1345-1348— cache hit short-circuits thewhoami.src/libswamp/auth/whoami.ts:141-148— whoami has the fresh scopes in hand and does not callsaveScopeCache. Grep confirmssaveScopeCachehas exactly one caller:mod.ts:1356.src/cli/commands/auth_logout.ts:42-47— hard refusal whenSWAMP_API_KEYis set.src/libswamp/auth/logout.ts:82-91— returns "not authenticated" before reachingdeleteCredentials()whenload()yields nothing.src/infrastructure/persistence/auth_repository.ts:217-227—delete()does removescope_cache.json, but is unreachable in the above case.
Deterministic repro
A — the cache cannot be cleared
export SWAMP_HOME="$(mktemp -d)"; mkdir -p "$SWAMP_HOME/config"
printf '{"fingerprint":"swamp_org_ab","scopes":["vault:*"]}\n' \
> "$SWAMP_HOME/config/scope_cache.json"
SWAMP_API_KEY=[REDACTED-SECRET-1] collective token> swamp auth logout
# -> Error: Authenticated via SWAMP_API_KEY environment variable. Unset it to log out.
swamp auth logout # env var unset; no auth.json exists (the CI case)
# -> Not currently authenticated.
ls "$SWAMP_HOME/config/scope_cache.json" # still thereBoth doors are shut: the first because the env var is set, the second because there are no credentials to delete. The stale scopes survive.
B — whoami and the gate disagree
Same SWAMP_HOME, with the cache above and an unreachable SWAMP_CLUB_URL:
swamp vault create @swamp/aws-sm v1
# -> passes the vault:* gate (proceeds to an unrelated downstream error),
# entirely from cache, with no network reachable
swamp auth whoami
# -> Error: Request to <swamp-club>/api/whoami timed out after 15s.The gate answers offline from a file; whoami only ever asks the server. With the network up, the same split produces the worse version: whoami prints Scopes: datastore:* while the very next command reports "Your collective token lacks the datastore:* scope."
Impact
This is the recovery path for every scope error, and it is a dead end. A user who hits "lacks the X scope", adds X to the token in the web UI, and re-runs gets the identical error forever. The diagnostic they will reach for — swamp auth whoami — actively confirms the token does have the scope, which reads as a CLI bug rather than a stale cache. The only remedy is rm ~/.config/swamp/scope_cache.json, which is documented nowhere.
It also means scope revocation never propagates: narrowing or removing a scope has no effect on any machine that cached before the change, for as long as the token itself is not rotated.
Expected
- Give the cache a TTL (and/or store the token's
updatedAtfrom the server) so scope changes converge without rotation. - Have
swamp auth whoamiwrite through to the cache — it already has authoritative scopes in hand, and it is the natural "refresh" gesture. - Make the cache clearable: either let
swamp auth logoutremove it even whenSWAMP_API_KEYis set / noauth.jsonexists, or add an explicitswamp auth cache clear/--refresh. - When rendering scopes in
whoami, distinguish live from cached so the two can be compared.
Related
- #1381 — unresolved scopes rendered as "lacks the scope".
- #1382 — the cache key itself collides across collective tokens.
Environment
- Verified against source
main@10943ef. The gate shipped ina519305(#1934), 2026-07-23; installed stable20260722.210030.0-sha.7ff1e2f0predates it. - macOS 14.
Closed
No activity in this phase yet.
magistr commented 7/24/2026, 9:58:21 PM
Author follow-up: I checked the published manual, and it strengthens rather than weakens this report.
/manual/reference/api-key-authentication documents credential storage as auth.json with mode 0600 and makes no mention of scope_cache.json. Neither /manual/explanation/api-key-scoping nor /manual/how-to/authenticate-with-api-keys refers to scope caching, cache lifetime, or any way to refresh or clear it.
So the file that actually decides whether a team-feature command succeeds is absent from the documentation entirely. A user whose token was updated on the website has no documented reason to suspect a local cache exists, no documented command to clear it, and — per the body of this issue — no undocumented one either, since logout is unreachable in the collective-token case. Whatever TTL or refresh mechanism gets chosen, the file is worth naming in the credential-storage reference alongside auth.json.
Sign in to post a ripple.