Your tokens. Your keys. We can't read them.
TapAuth is built on a zero-knowledge architecture. We broker OAuth tokens for AI agents — but we never have the ability to decrypt what we store.
Your LLM Never Sees Your Credentials
The problem: Most agent auth solutions pass credentials through the LLM's context window. If the conversation is logged, cached, or leaked — so are your keys.
How TapAuth solves it: The TapAuth CLI runs as a subprocess. It handles all credential operations — grant creation, secret storage, token retrieval — in a shell process the LLM never reads. The LLM calls the CLI, the CLI returns a bearer token. The grant secret (which is the decryption key) stays in ~/.tapauth/grants.json on your machine.
Even if your entire LLM conversation is logged or exfiltrated, no credentials are exposed. The agent gets a short-lived bearer token — not the keys to the kingdom.
Zero-Knowledge Token Storage
How it works: Every grant's tokens are encrypted with a unique key derived from the grant_secret using HKDF-SHA256. TapAuth never stores the grant_secret or the derived encryption key.
What we store: A one-way verification hash (cryptographically independent from the encryption key) and the encrypted token blob. That's it.
What this means: Even with full database access, stored tokens are unreadable ciphertext. There is no master key, no admin override, no backdoor. Same model as 1Password's Secret Key.
Current state: Tokens are currently encrypted at rest with AES-256-GCM. Per-grant zero-knowledge encryption is shipping soon — making TapAuth unable to decrypt stored tokens even with full server access.
You Hold the Only Key
The grant_secret: When you create a grant, you receive a grant_secret (prefixed gs_). This isn't just an API key — it's the root of your encryption key. TapAuth returns it once and never stores it.
What happens if you lose it: Tokens are permanently unrecoverable. By design. The agent must create a new grant and the user must re-approve. This is a feature, not a bug.
Revocation: Delete the grant, tokens are gone. No lingering access, no orphaned credentials.
Blast Radius of One
Per-grant isolation: Each grant has its own encryption key, its own scoped OAuth permissions, its own lifecycle. Compromising one grant_secret exposes exactly one grant's tokens — nothing else.
Contrast: Traditional OAuth brokers encrypt all tokens with a single server key. One breach = every user's tokens. TapAuth's per-grant encryption means one breach = one grant.
Scoped by design: Grants request only the specific OAuth scopes needed. A grant for calendar.readonly can't read your email.
Threat Model
| Attacker has... | What they get |
|---|---|
| Database access only | Encrypted blobs. No keys to decrypt them. |
| Server environment (ENV) only | No tokens to decrypt. |
| Database + ENV access | Nothing (post zero-knowledge migration). Legacy grants only during transition. |
| One grant_secret | That one grant's tokens. Nothing else. |
| Full server compromise | Only unclaimed tokens in ≤10 minute staging window. |
The Technical Details
crypto.randomBytes), 32 bytes of entropycrypto.timingSafeEqual) — no timing oracles