Koder Keys — Zero-Knowledge Password Manager
- Area: Foundation
- Path:
services/foundation/pass/app/(Flutter client, renamed fromapps/keysper RFC-001) +services/foundation/id/platform/services/keys/(Go backend service) - Kind: Zero-knowledge vault — client app + Koder ID microservice
Role in the stack
Koder Keys is Koder's built-in password manager. It follows the zero-knowledge model: the server stores only encrypted blobs — it never sees plaintext passwords, notes, or card numbers. Decryption happens exclusively on the client using a Master Unlock Key (MUK) derived from the user's master password + Secret Key via Argon2id + HKDF-SHA256.
The backend is the 7th microservice of Koder ID (platform/id/services/keys/), defined in RFC-014. It exposes a gRPC API for vault CRUD operations (bootstrap, createreadupdate/delete items, folder management, version history) and integrates seamlessly with Koder ID's authentication stack.
Cryptographic model
- Master password + Secret Key (34-char) → Argon2id (m64 MB, t3, p=4) → MUK
- MUK → HKDF-SHA256 → Vault Decryption Key (VDK)
- VDK → AES-256-GCM per item
- Secret Key is generated on first bootstrap and printed as an emergency kit. Loss of both master password and Secret Key = irrecoverable vault (by design).
Vault item types
login, card, note, totp, ssh_key — all five in schema from day one; v1 UI ships login only.
Primary couplings
| Module | Relationship |
|---|---|
platform/id |
Auth gateway — all vault RPCs require a valid Koder ID session |
platform/kdb (kdb-next) |
Storage substrate — vaults, items, folders, versions in TiKV |
apps/pass |
Sibling — Pass handles TOTP + passkeys; Keys handles passwords + cards |
Client shipping order
CLI (kode keys) → Koder Kodix secret-service adapter → Chromium extension → Flutter mobile (apps/keys)
OAuth Token Vault (ticket KEYS-039)
The keys service also acts as an OAuth token vault for server-to-server integrations with third-party providers (Google, Microsoft, GitHub). Other Koder services retrieve valid access tokens without implementing their own refresh logic.
Storage
- Table
keys_oauth_tokens— one row per provider+account pair, per tenant - Table
keys_service_account_keys— service account JSON key files - All secrets encrypted at rest with AES-256-GCM (
KEYS_OAUTH_PASSPHRASE) - Tenant isolation: kdbnext keyspace prefix + runtime check
Background refresh
A goroutine wakes every 5 minutes, finds tokens expiring within 10 minutes, and calls the provider token endpoint to refresh them. After 3 consecutive failures a token is marked refresh_failed and the consuming service must prompt the user to re-authorise.
HTTP API (internal)
Exposed on the existing HTTP port (default 4017):
| Method | Path | Description |
|---|---|---|
POST |
/oauth/tokens |
Store new token |
GET |
/oauth/tokens/:id |
Get token (auto-refresh if < 5 min left) |
GET |
/oauth/tokens/by/:provider/:email |
Get by provider+email |
DELETE |
/oauth/tokens/:id |
Revoke and delete |
GET |
/oauth/tokens?user_id=X |
List user tokens |
POST |
/oauth/service-accounts |
Store service account key |
GET |
/oauth/service-accounts/:id |
Get service account key |
GET |
/oauth/service-accounts/:id/jwt |
Get signed JWT (cached 55 min) |
DELETE |
/oauth/service-accounts/:id |
Delete service account key |
Required env vars: KEYS_OAUTH_PASSPHRASE, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET. Maintenance: see meta/context/credentials/google-runbook.md.
RFCs
- RFC-014 — Vault service architecture (zero-knowledge model, crypto spec, schema, gRPC API)
See platform/id/docs/rfcs/RFC-014-vault-service.md.