Enforcer
SpiceDB is an open source authorisation database inspired by Google's Zanzibar paper, and AuthZed is the company behind it. You define a schema, write relationship tuples into SpiceDB as a separate database, then ask it whether a subject has a permission on a resource, or call LookupResources to list what a subject can access. The engine is Apache-2.0 on GitHub, created in August 2021, and carries 7,054 stars today. This page is written by the team behind Enforcer, so read it with that in mind. Every claim below links to the source it came from, and the part about Enforcer's weaknesses is longer than the part about its strengths, because that is the honest ratio.
LookupResources answers "which resources can this user see" by walking the graph at request time, and AuthZed's own FAQ is explicit about where that fits: "LookupResources - Use when the number of accessible resources is relatively small. Call LookupResources to get all resource IDs the user can access, then use those IDs as a filter in your database query (e.g., WHERE id = ANY(ARRAY[...])). This is the simplest approach and a good starting point." A 2021 proposal for a precomputed permission index, the Lookup Watch API and Tiger Cache, opened on 22 October 2021, was closed as not planned on 17 December 2025. On that thread in May 2024 AuthZed wrote: "As a result, we took a different approach entirely when building our Materialize product, which is currently proprietary and sold as a managed service." The same comment continues: "That being said, our company philosophy is that these types of critical systems need to be open source. We've developed the project with the ultimate goal of open sourcing when the time is right." As things stand today, Materialize "maintains continuously updated materialized views of your SpiceDB permissions" and is "Available to AuthZed Dedicated users as part of an early access program", so the precomputed fast path is not in the Apache-2.0 engine.relation viewer and relation new_viewer", backfill, drop the old relation from the permission, update the application again so it stops writing the old relation, and only then delete it. Two of those six steps are application deploys. If your permission model is still moving, every change is a coordinated release.Stay on SpiceDB when your requirement is answering "which resources can this user see" across a large relationship graph, with nested groups, folder hierarchies and inherited sharing. That is the problem Zanzibar was designed for, and SpiceDB is an Apache-2.0 implementation of it that you can run yourself, with datastore guidance that recommends CockroachDB for self-hosted deployments with high throughput or multi-region requirements, Cloud Spanner on Google Cloud, and PostgreSQL for single-region deployments, while MySQL is marked "Not recommended; only use if you cannot use PostgreSQL". AuthZed is also working on the second-database complaint directly: a PostgreSQL foreign data wrapper shipped in v1.49.0 exposes permissions as virtual tables you can join against your own rows in SQL, and AuthZed says "The SpiceDB FDW today is experimental, but it has been fairly well tested and designed with real-world use cases in mind." If you filter large lists by permission, or you want an engine you can fork and self-host, nothing on this page replaces SpiceDB, Enforcer included.
| Option | Model | Strength | Trade-off |
|---|---|---|---|
| OpenFGA | Zanzibar-style relationship engine, CNCF incubating project | The same relationship model under vendor-neutral governance: openfga.dev states "We are a Cloud Native Computing Foundation incubating project." Its docs name three query endpoints: Check, "returning whether the user has a certain relationship with an object", ListObjects, which "returns all objects of a given type that a user has a specified relationship with", and ListUsers, which "returns all users of a given type that have a specified relationship with an object". | It keeps relationship data of its own, so the second store and the writes that keep it current come with it, exactly as they do with SpiceDB. You also run and operate the engine yourself. |
| Cerbos | Stateless policy decision point, YAML policies | No authorisation database to keep in sync. Cerbos describes a "Stateless design enabling sub-millisecond policy evaluation without having to synchronize application state or rely on slow network fan-out", and the same page offers a route to list filtering: "Decouple data filtering requests from the code via a query plan API, managed by the same policies as application access." | Policies are YAML you own and move yourself. The page frames that as a feature, "Define policies in YAML, Human readable configurations for better cross-functional collaboration", and says you "Manage, test and deploy fine-grained access control policies using a CI/CD/GitOps workflow", which means policy distribution, review and rollback are your pipeline's job rather than a console's. |
| Open Policy Agent | General-purpose policy engine, Rego, CNCF graduated | One policy language across application authorisation, Kubernetes admission control, CI and infrastructure. The docs describe "an open source, general-purpose policy engine that unifies policy enforcement across the stack" and state "OPA is proud to be a graduated Cloud Native Computing Foundation (CNCF) project." | General purpose cuts both ways. OPA is a policy engine rather than an identity or permissions product, so the data model, where the facts live and how they reach a decision are all yours to design, and Rego is a real learning curve on top of that. |
| Oso Cloud | Hosted authorisation service, Polar language, stores facts | One language covering roles, relationships and attributes together. Oso describes "a centralized authorization service built on Polar, our logic programming language designed for expressing permission systems, and SQLite, the world's most battle-tested database engine", and a query returns "a boolean, list, or logic to execute against your database", so list filtering is in scope. | The open source library at osohq/oso is Apache-2.0 and not archived, but its README now opens with "We have deprecated the legacy Oso open source library", while adding "we are not end-of-lifing (EOL) the library" and promising critical bug fixes. The actively sold product is the hosted service, and you still push authorisation facts into it. |
| WorkOS FGA | Fine-grained authorisation inside an identity platform | Authorisation sits next to the identity you already need. The docs say it "integrates natively with WorkOS products you're already using: RBAC, SSO, Directory Sync, AuthKit, and IdP role assignment", and it answers "Which resources can this user access?" and "Who has access to this resource?" as well as the single-check question. | It is a commercial platform, so adopting it for authorisation means adopting WorkOS for identity too. The FGA docs page publishes no pricing, so budgeting means a conversation. |
Enforcer is a different shape, not a better Zanzibar. Identity and authorisation are one service: it signs the user in (email OTP, passkeys, wallet sign-in, enterprise SSO) and holds tenants, roles and groups, so a policy is handed an already-resolved caller rather than one your application had to look up and pass in. POST /authz/check returns { success, allow, reason }, and a policy_id only when you sent one on the request, because that field is echoed from your input rather than filled in by the engine. Custom policies are Rego in package enforcer.custom, compiled at write time, capped at 64KB with a 100ms evaluation budget. Enforcer is listed in the MCP registry as dev.instruxi.enforcer/v3, with the endpoint at https://api.instruxi.dev/mcp over streamable HTTP.
Where it is worse, plainly. List filtering only over Enforcer’s own resource types. The engine compiles the same policy into a SQL WHERE clause by partial evaluation, exposed over gRPC as CompileFilter, but only for the eleven types registered in Enforcer’s own process (account, group, tenant, ticket, wallet and six more). There is no REST endpoint for it and no way to register your own tables, so you cannot use it to filter your application’s data. It cannot answer "give me every resource this user can read" over your tables. SpiceDB, OpenFGA, Cerbos, Oso Cloud and WorkOS FGA all answer a list question in some form, as quoted above; Enforcer answers one call about one resource. If list filtering is your requirement, Enforcer is the wrong tool. No shadow or preview evaluation. An inactive policy is stored and simply not evaluated, so there is no way to dry-run a change against live traffic before a cutover. No decision log out of the box. GET /audit-events is the identity and admin trail, for logins, API keys, roles, tenants and terms. It never records authorisation decisions, so you log the returned reason yourself. The resource is an assertion. On /authz/check the resource is described by the caller and never looked up, so owner_id is a claim your application must resolve server side or the check means nothing. The baseline is not default-deny. Before you write any rule, a built-in policy already allows any action other than manage on a row the caller owns, plus group and group type reads in your tenant, your own audit events and global policies; our internal audit also records that holders of tenant_read can take any non-read action on a ticket in their tenant without owning it, and an admin with cross_tenant gets everything. A named policy replaces that decision rather than intersecting with it, so a rule never tightens the baseline for a call that does not name it, and contexts only reaches a named policy, because the built-in path ignores it. Creating a policy requires tenant admin. And we are small and new, with no independent reviews and no large community, next to an Apache-2.0 SpiceDB repository created in August 2021 that carries 7,054 stars today.
Sources checked 15 September 2026: github.com/authzed/spicedb · github.com/authzed/spicedb/issues/207 · github.com/authzed/spicedb/issues/207#issuecomme · authzed.com/blog/the-dual-write-problem · authzed.com/blog/spicedb-postgres-fdw · authzed.com/docs/spicedb/getting-started/faq · authzed.com/docs/spicedb/concepts/consistency · authzed.com/docs/spicedb/concepts/datastores · authzed.com/docs/spicedb/modeling/migrating-sche · authzed.com/products/authzed-materialize · openfga.dev/ · openfga.dev/docs/concepts