Enforcer

AuthZed and SpiceDB alternatives

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.

Why teams go looking

When to stay

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.

The options

OptionModelStrengthTrade-off
OpenFGAZanzibar-style relationship engine, CNCF incubating projectThe 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.
CerbosStateless policy decision point, YAML policiesNo 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 AgentGeneral-purpose policy engine, Rego, CNCF graduatedOne 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 CloudHosted authorisation service, Polar language, stores factsOne 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 FGAFine-grained authorisation inside an identity platformAuthorisation 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.

Where Enforcer fits, and where it does not

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

Enforcer is identity and authorization in one system, for applications and AI agents. Docs at docs.instruxi.dev. Related: Authorization tools compared · Why was this request denied? · OpenFGA alternatives · Cerbos alternatives · Permit.io alternatives