Relationships
#1825 access token mint: plaintext secret never surfaced to user, vault read-secret cannot access _token-secrets
Opened by webframp · 8/25/2026· Shipped 8/26/2026
Summary
After minting a server token with swamp access token mint, there is no working path to retrieve the token secret. The CLI output instructs the user to run swamp vault read-secret _token-secrets <key> --yes, but that command fails with "Vault not found" because the _token-secrets control-plane vault is not registered in the vault CLI's VaultService.
How We Hit This
We were testing whether lab issue #1684 (swamp serve OOM on 2000+ model repos) is fixed in build 20260825.200043.0. Serve boots fine now (confirmed with 2335 models, 62 extension types — great work on the fix). But we couldn't authenticate against the running instance because we couldn't obtain the token secret after minting.
I may be misunderstanding the intended bootstrap flow for swamp serve --auth-mode token, but after reading the source I believe the retrieval path is genuinely broken rather than a usage error on my part.
Steps to Reproduce
- Start serve:
swamp serve --auth-mode token --admins user:webframp --no-schedule - Mint a token:
swamp access token mint test-token --principal user:webframp --duration 1h - Output says:
Retrieve the token with: swamp vault read-secret _token-secrets server-token-test-token --yes - Run that command:
swamp vault read-secret _token-secrets server-token-test-token --yes - Error:
Vault not found: '_token-secrets'. Available vaults: my-vault, jfrog, loadgen-02-vault
No way to retrieve the secret means no way to form the name.secret string needed for swamp auth server-login --token.
Code Path Analysis
Where the plaintext exists
In src/domain/models/access/server_token_model.ts, the mint method:
const plaintext = generateOpaqueToken();
await context.vaultService.put(args.vaultName, secretKey, plaintext);The plaintext is written to the vault and then discarded — it's never returned in the method result.
The doc comment vs implementation gap
src/libswamp/access/token_create.ts line 27 states:
"reads the plaintext back from the vault so the CLI can show it exactly once"
But the implementation of serverTokenCreate only extracts tokenRecord.secretKey (the key name: e.g. "server-token-test-token") from the data artifacts — it never calls vault.get() to retrieve the actual secret value. The ServerTokenCreateData interface has no field for the plaintext.
Why vault read-secret fails
vault read-secret uses VaultService.fromRepository() which loads user-defined vaults from vaults/ and merges in global providers (line 181 of vault_service.ts). But global providers are process-static — registerGlobalProvider is only called by:
- The serve process at boot (
serve.ts:1774) - The
access token mintcommand viainitializeControlPlaneVaultForCli
The vault read-secret command never calls initializeControlPlaneVaultForCli, so _token-secrets is never in its provider map.
The encrypted file exists but is inaccessible
$ cat .swamp/_control/token-secrets/values/server-token-test-token
{"iv":"...","data":"...","version":1}The secret is there, AES-GCM encrypted with the key at .swamp/_control/token-secrets/encryption-key. But there's no supported CLI command that decrypts it.
Expected Behavior
One of:
swamp access token mintshould display the fullname.secrettoken string at mint time (show-once pattern, as the doc comment describes)swamp vault read-secret _token-secrets <key>should work by having the vault CLI initialize the control-plane vault provider when the requested vault is_token-secrets
Option 1 seems more aligned with the stated intent and standard token UX.
Environment
- swamp 20260825.200043.0-sha.3ba23b09
- Linux (NixOS 26.11)
- Repo: 2335 models, 62 extension types, filesystem datastore
- Vault backend: @swamp/aws-sm (user vaults), local filesystem (control-plane)
Shipped
Click a lifecycle step above to view its details.