Fine‑Grained, Context‑Aware Authorization with SpiceDB’s Dynamic ACLs and Policy Templates
Learn how SpiceDB’s dynamic ACLs and policy templates let you write reusable, attribute‑based rules that adapt at request time. A concrete example, trade‑offs, and next steps are provided to help you decide if SpiceDB fits your app’s security needs.
20 Nov 2025, 14:16 UTC

Why you need context‑aware rules
Traditional role‑based access control (RBAC) hard‑codes permissions in a flat table. When the business logic depends on object metadata—like a document’s tags, owner, or classification—RBAC becomes a maintenance nightmare. SpiceDB solves this by evaluating policies at request time, letting rules reference object attributes directly. The result is a single source of truth that adapts automatically as data changes.
Core concepts: dynamic ACLs and policy templates
- Dynamic ACLs: Policies that reference attributes on the target object. Example: “allow read if object has tag ‘public’.” The ACL is re‑evaluated for each request, so updating the tag instantly changes access.
- Policy templates: Parameterized rule patterns that you can instantiate for many objects. Templates reduce duplication and make large policy sets easier to maintain.
- gql (GraphQL‑like query language): SpiceDB’s policy engine uses a small, expressive language to declare rules. It supports recursion (e.g., hierarchical groups) but enforces a depth limit to avoid infinite loops.
- Cache: A built‑in in‑memory cache that stores the results of recent evaluations, drastically reducing latency on repeated checks.
Concrete example: “public” tag grants read access
Assume you have a collection of documents stored in a database. Each document has an attribute tags (array of strings). You want any user to read a document if it carries the public tag.
- Create a policy template
# Run on the SpiceDB server (requires admin privileges) spicedb create-policy-template \ --name read-public \ --resource-type document \ --condition "document.tags contains 'public'"Explanation:
--nameis an identifier for the template.--resource-typespecifies the SpiceDB type you’re authorizing.- The
--conditionis a gql expression that evaluates to true when the object’stagsarray contains the stringpublic.
- Instantiate the template for a specific document
# Assume document ID is abc123 spicedb create-policy \ --template read-public \ --resource-id abc123 \ --effect allow \ --action readThis creates a concrete policy that applies the template condition to the document with ID
abc123. - Evaluate access for a user
# User alice wants to read abc123 spicedb authz \ --user alice \ --resource document:abc123 \ --action readExpected outcome:
ALLOWif the document’s tags includepublic; otherwiseDENY. The engine logs the evaluation path, including any policy references and the final decision. - Verify the result
Run the same command after removing the
publictag from the document. The response should now beDENY, proving the rule is truly dynamic.
Trade‑offs and limitations
- Recursion depth: Policies that reference other policies (e.g., group membership) can hit the engine’s recursion limit (default 10). Exceeding it aborts evaluation with a clear error. Design policies with bounded depth and test with
spicedb authz --debugto catch early. - Template parameter safety: If you bind variables from untrusted input, you risk unintentionally granting access. Always validate parameters before instantiation, and use the policy viewer to audit active rules.
- Database indexing: SpiceDB stores policy and object data in PostgreSQL. Missing or incorrect indexes on columns used in
--conditionexpressions can lead to slow evaluations. Ensuretagsis indexed as aGINarray column. - Over‑permissive defaults: A catch‑all policy that allows all actions can expose data if not overridden. Use the
spicedb policy-viewerto inspect the effective policy set before deploying.
Performance considerations
The cost of an authorization check grows with the number of matching policies. In benchmarks with 10,000 policies, enabling the built‑in cache reduced average latency from ~120 ms to ~15 ms. To benefit:
- Keep the cache enabled (
spicedb start --enable-cache). - Group related policies into templates to avoid duplication.
- Periodically run
spicedb policy-viewer --compactto identify and prune unused rules.
Actionable next steps
- Deploy a local SpiceDB instance (
docker run -p 50051:50051 ghcr.io/authzed/spicedb:latest) and import your existing object schema. - Start with a single policy template (like the
publicexample) and iterate on more complex conditions. - Enable the cache and monitor
spicedb metricsfor hit rates. - Use the policy viewer to audit the effective policy set after each change.
- Automate policy evaluation tests in your CI pipeline (e.g.,
spicedb authz --user test --resource ...).
By separating policy logic from data and leveraging dynamic ACLs, SpiceDB lets you write flexible, maintainable authorization rules that adapt automatically as your data evolves. If your application needs fine‑grained, context‑aware access control without the overhead of custom code, SpiceDB’s policy templates and caching mechanisms provide a strong foundation to build on.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.