Relationships
↑ child of #662#674 serve-auth: client-side server credential storage
Opened by stack72 · 6/17/2026· Shipped 6/18/2026
Parent
Sub-issue of #662 (serve authentication & authorization). Layer 1, item 6.
Summary
Implement client-side storage for server credentials — the token a user receives after authenticating with a swamp serve instance. This is the client-side half of user authentication; the server-side token model is a sibling issue (#673, item 5).
Today `~/.config/swamp/auth.json` stores exactly one swamp-club credential (`src/domain/auth/auth_credentials.ts` + `src/infrastructure/persistence/auth_repository.ts`). Server credentials are a sibling aggregate: a `ServerCredential` keyed by normalized server URL, persisted to a separate file with the same precedence pattern.
What to build
Domain type
A `ServerCredential` value object in `src/domain/auth/`:
```typescript interface ServerCredential { serverUrl: string; // normalized URL (e.g. "https://swamp.acme.internal:9090") tokenName: string; // the name portion of the . token token: string; // the full . plaintext principalId: string; // the user's sub from the OAuth login displayName?: string; // the user's display name (for swamp auth whoami --server) obtainedAt: string; // ISO timestamp of when the credential was obtained } ```
Persistence
A `ServerCredentialRepository` in `src/infrastructure/persistence/`:
- File: `~/.config/swamp/servers.json` (or `$XDG_CONFIG_HOME/swamp/servers.json`)
- Permissions: mode `0o600` (same as `auth.json`)
- Format: JSON object keyed by normalized server URL
- Precedence: `SWAMP_SERVER_TOKEN` env var > `servers.json` file (same pattern as `SWAMP_API_KEY` > `auth.json`)
Repository interface
```typescript interface ServerCredentialRepository { get(serverUrl: string): Promise<ServerCredential | null>; save(credential: ServerCredential): Promise; remove(serverUrl: string): Promise; list(): Promise<ServerCredential[]>; } ```
URL normalization
Server URLs must be normalized before use as keys — strip trailing slashes, lowercase the hostname, default port handling. This prevents `https://swamp.example.com\` and `https://swamp.example.com/\` from being treated as different servers.
Environment variable override
When `SWAMP_SERVER_TOKEN` is set, it provides a token for use with `--server` commands without needing a `servers.json` entry. Follow the same pattern as `SWAMP_API_KEY` in `src/infrastructure/persistence/auth_repository.ts`.
Scope
- `ServerCredential` type in `src/domain/auth/`
- `ServerCredentialRepository` interface in `src/domain/auth/`
- File-based implementation in `src/infrastructure/persistence/`
- URL normalization utility
- Unit tests: save/get/remove/list, file permissions, env var override, URL normalization
- No CLI commands (the `swamp auth login --server` command that writes credentials is layer 4)
Out of scope
- Server token model (server-side) — #673
- `swamp auth login --server` CLI command — layer 4
- OAuth login flow — layer 4
References
- Existing auth credentials: `src/domain/auth/auth_credentials.ts`
- Existing auth repository: `src/infrastructure/persistence/auth_repository.ts`
- Config dir resolution pattern: follow how `auth.json` finds its path
Shipped
Click a lifecycle step above to view its details.