Authorization starts as a column. You add role to the users table, branch on admin in a few places, and it works for a year. Then a customer asks whether their contractor can see one folder but not the invoices in it, and someone notices a manager can approve their own reimbursement. Neither fits in a column.
The concrete version: Amazon Verified Permissions charges $0.000005 per single authorization request, a price that only makes sense because real apps ask the question thousands of times per page render. And Cerbos bills per "monthly active principal," spelling out that a principal is a user or a service, bot, or other non-human identity, so 3,000 users plus 15 machine identities is 3,015 principals. The vendors have already priced for agents.
Quick Comparison
| Tool | Shape | Stars | License | Hosted pricing | Best for |
|---|---|---|---|---|---|
| OpenFGA | Relationship | 5,637 | Apache 2.0 | Via Auth0 FGA | Zanzibar model with CNCF governance |
| SpiceDB | Relationship | 6,978 | Apache 2.0 | From $2/hr (AuthZed Cloud) | Highest scale, consistency controls |
| Ory Keto | Relationship | 5,388 | Apache 2.0 | Ory Network | Teams already on the Ory stack |
| Cerbos | Policy | 4,547 | Apache 2.0 | PoC $0, Development from $25/mo | Conditional rules, no data migration |
| OPA | Policy | 12,130 | Apache 2.0 | Self-hosted | Infra policy alongside app authz |
| Cedar | Policy | 1,679 | Apache 2.0 | $0.000005 per request via AVP | AWS-native apps wanting a managed PDP |
| Permit.io | Control plane | 5,501 (OPAL) | Apache 2.0 (OPAL) | Startup from $5/mo, Pro from $25/mo | Teams needing a permissions UI |
| Apache Casbin | Library | 20,334 | Apache 2.0 | None, embedded | Embedding authz in one service |
| Oso | Control plane | 3,492 | Apache 2.0 | Contact sales | Agent oversight |
All GitHub numbers were read from each repository on August 21, 2026.
The Two Shapes
Picking the wrong architecture costs more than picking the wrong vendor inside one. Relationship engines descend from Google's Zanzibar paper: you store tuples (user:anna is member of team:platform) in the engine's own database, model how relations imply others, and let it traverse the graph. Strong at sharing hierarchies and at listing because the engine owns the data; the cost is that permission data lives outside your primary store and must stay in sync as your app creates resources. Policy engines keep no state: you write policy as code, run a decision point beside your service, and pass the principal, resource, and attributes per request. Microseconds, no database hop, policies in Git, but you supply the context and "which objects can this user see" is your problem again. The hybrids (Permit.io, Oso Cloud, WorkOS FGA) sit on one of these and sell the control plane.
Relationship Engines

OpenFGA came out of Auth0 and moved to CNCF Incubating maturity on October 28, 2025, three years after acceptance, which helps in an architecture review. The modeling language reads close to English and ListObjects is first-class. The catch is operational: a stateful service plus a sync path that writes a tuple whenever your app creates a shareable resource, and nothing stops you from forgetting a write.

SpiceDB from AuthZed is the most established Zanzibar implementation, and its differentiator is consistency control. A permission revoked a millisecond ago may still be cached, so SpiceDB exposes explicit consistency levels, including a ZedToken requiring a read as fresh as your last write. Pricing is by deployment: open source free, AuthZed Cloud advertised as "deploy a permissions system for $2/hr" with $700 in starter credits, self-hosted enterprise licensed per region and vCPU. The heaviest operational commitment here.
Ory Keto suits teams already running Kratos and Hydra.
Policy Engines

Cerbos takes the opposite bet: your data stays put and the engine stores no permissions. You run the PDP as a sidecar, keep policies as YAML in Git, and pass attributes with every check. The open-source PDP is free forever; Cerbos Hub adds a control plane, with a Proof of Concept tier at $0/mo up to 100 monthly active principals and Development from $25/mo. Conditional logic is where this shape wins. Listing is the weak spot, needing the query-planner API to produce a database filter.

Cedar is the policy language AWS open-sourced and wrapped in a managed service, built for formal analysis so you can reason about policy conflicts instead of finding them in production. Pricing is the clearest here: $0.000005 per single authorization call, and batch calls metered per call regardless of how many decisions they contain, at $0.00015 for the first 40 million monthly, $0.000075 for the next 60 million, $0.00004 beyond. So batch the 50 checks a page needs into one call.
OPA at 12,130 stars is the policy engine you are most likely to already be running, though usually for infrastructure rather than app authorization. Extending it to app authorization avoids a second engine; otherwise Cerbos or Cedar start faster.
Control Planes and Libraries

Permit.io is the most complete control plane, with pricing published once you flip the "Show all plans" toggle: Community free forever, Startup from $5/mo (25,000 MAU, 100 tenants), Pro from $25/mo (50,000 MAU, 20,000 tenants), Enterprise unlimited. Open-source projects get Startup free. It also maintains OPAL, the policy and data sync layer underneath.
WorkOS FGA is the product formerly known as Warrant, acquired in April 2024. It fits if WorkOS is already your identity layer, but its pricing is not published alongside the AuthKit and SSO numbers, so treat it as a sales conversation.

Oso needs a caveat. It was one of the best-known names here on the strength of an embeddable library and the Polar language; its homepage now leads with "Agents are here. Oso makes them safe," and the open-source osohq/oso repository has not been pushed to since February 26, 2025. Check the repo yourself before building on the library.
Apache Casbin is the quiet giant: 20,334 stars, now undergoing incubation at the Apache Software Foundation (it ships as "Apache Casbin (Incubating)"), with implementations across Go, Java, Node, Python, PHP, .NET, and Rust. No network hop and no vendor, but no control plane and no answer for "which objects." Hard to beat for a monolith needing real ABAC.
Running OpenFGA Locally
OpenFGA server v1.18.3 and CLI v0.7.20, from release binaries because the Docker daemon was down. This model says a document inherits editors from its parent folder, and a folder grants editor to every member of a team:
texttype folder relations define editor: [user, team#member] type document relations define parent: [folder] define editor: [user, team#member] or editor from parent define viewer: [user, team#member] or editor or viewer from parent
Push it with fga store create --model model.fga, then write three tuples, none of which grants anything on the document directly: anna member team:platform, team:platform#member editor folder:engineering, folder:engineering parent document:roadmap. The checks are where the model earns its keep:
textfga query check user:anna editor document:roadmap -> {"allowed":true} fga query check user:bob editor document:roadmap -> {"allowed":false} fga query list-objects user:anna viewer document -> {"objects":["document:roadmap"]} fga tuple delete user:anna member team:platform -> {} fga query check user:anna editor document:roadmap -> {"allowed":false}
Anna reached that document through two hops she was never explicitly given, then lost it because she left a team, with no application code involved. list-objects is the query that replaces a hand-written SQL filter.
For contrast, Cerbos v0.55.0 against a policy where managers view and approve in their own region under $5,000, and nobody approves their own expense:
textmanager, us-east, $4,200, owned by anna view: ALLOW approve: ALLOW manager, us-east, $7,500, owned by anna view: DENY approve: DENY manager, us-east, $100, owned by dana view: ALLOW approve: DENY
The $7,500 row is denied for view too, because the manager's only matching allow rule carries the amount condition: the kind of bug you find by testing decisions, not reading rules. Row three is explicit deny beating allow, in three lines of policy.
How to Pick
Start from the question your product asks most often.
Users share resources and "list everything this user can see" must be fast: a relationship engine, OpenFGA for the gentlest curve, SpiceDB when scale or consistency-after-revocation is a hard requirement. Rules are conditions on attributes you already have: a policy engine, Cerbos for YAML in Git, Cedar on AWS, OPA if you already run it. Non-engineers need to define or audit permissions: a control plane, from $5/mo with Permit.io. One service, no plans for more: Apache Casbin.
Whichever shape you pick, decide early where permission data is written. The most common failure in relationship-engine adoptions is a code path that creates a resource without writing its tuple.
Moving Off a Roles Column
- Write the questions down, not the roles, as "can PRINCIPAL do ACTION on RESOURCE." Twenty of these cover most products and become your test suite.
- Model one resource type end to end against those tests, then run the engine in shadow mode beside the existing check and log disagreements.
- Flip one endpoint behind a flag, and replace list endpoints last, since a bug there shows wrong rows instead of throwing.
Conclusion
The choice is about where permission data belongs, not which vendor markets better. Relationship engines own the data and answer sharing and listing questions well. Policy engines own no data, answer conditional questions well, and use Git as the audit trail. Both are open source and run on a laptop, so test the fit before talking to sales.
Two things to watch: pricing units now count machine identities, which changes your bill once agents call your API for a customer, and the category is consolidating. Warrant became WorkOS FGA, Oso's library went quiet, OpenFGA moved up to CNCF Incubating. Check the repo and the pricing page on the day you decide.
Related DevToolLab Tools
- AWS IAM Policy Generator - sanity-check the IAM policy JSON that sits alongside Cedar or Verified Permissions.
- kubectl Command Generator - the
auth can-iand RBAC commands for checking Kubernetes permissions. - CSV to YAML Converter - turn a permission matrix spreadsheet into a starting point for policy YAML.
- SQL SELECT Builder - the filtered query that
ListObjectsis meant to replace.
Related Guides
- Best Authentication Providers in 2026 - the layer that answers "who is this" first
- Non-Human Identity Security - why machine identities outnumber your employees
- Only 8.5% of MCP Servers Use OAuth - agent tooling skipping authorization
- OWASP Top 10 for LLM Applications - excessive agency as a named risk
