# Cache Keying *Discovered 2026-04-06.* ## The gap Mizan specified invalidation but never specified cache keying. Without correct cache keying, Edge caching is a **security vulnerability** — it serves User A's content to User B. ## Why Vary doesn't work All major CDNs ignore `Vary` for personalized content. No standardized replacement exists. ## Resolution: HMAC cache key (JSON-canonical form) ``` HMAC-SHA256(secret, JSON.stringify({ "c": context, "p": sorted_params, "r": rev, "u": user_id // omitted for public content }, sort_keys=True)) ``` ### Key derivation rules - **Public content** — URL path + query params (standard CDN). - **User-scoped content** — HMAC key derivation above. - **`@client(auth=...)`** determines whether content is user-scoped. - **`rev` parameter** on `@client` for deploy-time logic invalidation. Bumped by the developer when function logic changes. ## Identity layer MWT (Mizan Web Token) — see [MWT_SPEC.md](MWT_SPEC.md). JWT with Mizan claims on `X-Mizan-Token` header. Replaces the old `JWTUser` + permission key metadata approach. ## Cache architecture *Decided 2026-04-06.* **Not a compiled binary ABI. Not a pluggable Python protocol.** Each backend adapter (Python, TypeScript, future PHP/C#/Go) implements the cache protocol in its own language, backed by Redis. **Conformance verified by a shared test suite.** ### Required operations - `cache_get` - `cache_put` - `cache_purge` - `cache_purge_user` ### Storage Redis only. Handles persistence, cross-worker sharing, crash recovery. ## Deploy invalidation No full context flush. The `rev` parameter on `@client` is part of the HMAC key. When the developer bumps `rev`, old cache entries become **unreachable orphans**. No purge needed; no thundering herd. ## Invariant All cache-related code must implement *identical* HMAC key derivation. Cross-language conformance tests enforce this. Any divergence is a security vulnerability.