Solving Causal Consistency in ReBAC with SpiceDB Zookies
Learn how to eliminate the 'New Enemy' problem in SpiceDB by implementing zookies to ensure causal consistency between authorization writes and reads.
14 May 2026, 08:20 UTC

The Problem: The 'New Enemy' Consistency Gap
\nIn a distributed Relationship-Based Access Control (ReBAC) system, a common failure mode is the lack of causal consistency. This occurs when a user is granted a permission (a write), but a subsequent authorization check (a read) hits a database replica that hasn't yet received that update. In security contexts, this is known as the 'New Enemy' problem: a user is removed from a sensitive group, but because of replication lag, they can still access the resource for several seconds.
\nThe takeaway is that eventual consistency is insufficient for authorization. To prevent unauthorized access during replication lag, you must use consistency tokens—referred to in SpiceDB as zookies—to ensure the check is performed against a snapshot of data at least as fresh as the last known change.
\nThe Smallest Suitable Design for Causal Consistency
\nTo implement causal consistency, the application must move from a stateless \"check\" pattern to a stateful \"token-passing\" pattern. The architecture requires three components: a relationship store (SpiceDB), a persistent storage backend (such as CockroachDB), and a client application that manages the zookie lifecycle.
\nThe Zookie Workflow
\n- \n
- Write Path: When the application updates a relationship (e.g., adding a user to a folder), the SpiceDB
WriteAPI returns a zookie. This token represents a specific point in the database's timeline. \n - Persistence: The application stores this zookie alongside the user's session or the object's metadata in its own primary database. \n
- Read Path: When the user attempts to access a resource, the application retrieves the stored zookie and passes it into the
CheckAPI request. \n - Verification: SpiceDB ensures the request is routed to a node or snapshot that has seen the transaction associated with that zookie before returning a boolean result. \n
Trust and Data Boundaries
\nA critical engineering decision in SpiceDB is the separation of Identity from Authorization. SpiceDB does not store user passwords, email addresses, or object metadata; it only stores the relationships between IDs.
\n- \n
- Application Boundary: The calling service is responsible for authenticating the user and mapping a session to a
subjectID (e.g.,user:123). \n - SpiceDB Boundary: SpiceDB is the single source of truth for the graph. It trusts the application to provide the correct IDs but does not verify if those IDs exist in the application's primary database. \n
- Consistency Boundary: The zookie acts as the bridge between the write-path and the read-path, ensuring the application's view of the world is consistent with the authorization engine's view. \n
Implementation Example: Causal Check
\nConsider a scenario where a user is promoted to an admin role. Without a zookie, a rapid succession of requests might result in a 403 Forbidden because the read hit a stale replica.
# 1. Update relationship (Run via SpiceDB API/CLI)\n# Permission: user:alice is now an admin of organization:engineering\n# Expected result: Returns a zookie (e.g., \"zookie_v1_12345\")\nspicedb write relationship organization:engineering#admin user:alice\nTo verify the permission immediately, the application must include that specific token in the check request:
\n# 2. Perform Check with Zookie\n# Command: spicedb check --zookie \"zookie_v1_12345\" --subject user:alice --relation admin --object organization:engineering\n# Expected result: True\nRisk: If the --zookie flag is omitted, SpiceDB may return a result based on the local node's current state, which could be stale, leading to intermittent authorization failures during high-write volumes.
Operational Checks and Failure Modes
\nDiagnostic Decision Table
\n| Symptom | \nLikely Cause | \nVerification Step | \n
|---|---|---|
| Intermittent 403s after a grant | \nMissing or stale zookies | \nCompare Check results with and without the latest zookie. | \n
Increased latency on Check | \nDeep graph traversal | \nAnalyze the schema for recursive relation definitions that create long chains. | \n
| Zookie \"Too Old\" Errors | \nStorage cleanup/TTL | \nCheck the retention policy of the underlying database snapshots. | \n
Failure Modes
\n- \n
- Deep Nesting: If your schema defines permissions as
user > group > sub-group > folder > file, SpiceDB must perform multiple recursive lookups. This can lead to latency spikes. \n - Zookie Loss: If the application fails to persist the zookie, it must fall back to a \"global\" consistency level, which may increase latency as the system ensures it is reading the most recent data across the cluster. \n
Conditions for Design Change
\nThe zookie-based architecture is optimal for most ReBAC needs, but you should reconsider this design if:
\n- \n
- Ultra-Low Latency Requirements: If the millisecond overhead of zookie validation is unacceptable, you may need to move to a cached permission model, accepting the risk of temporary staleness. \n
- Massive Fan-out: If a single subject is a member of thousands of groups, the graph traversal may become a bottleneck, requiring a flattening of the relationship schema. \n
To verify the result of your implementation, deploy a test instance and execute a Write followed immediately by a Check without a zookie. Repeat this in a loop; if you see any False responses for a granted permission, your system is experiencing the consistency gap and requires zookie integration.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.