Choose a permission model
Choose the model that describes how your application grants access. Every model stores permission data and provides check and list functions you can call from your backend. You can use more than one model in the same database. RLS is optional and independent of this choice.
| Your rule | Start with | Example |
|---|---|---|
| A role grants access across the application | App-wide RBAC | Editors can edit documents. |
| A role grants access within an organization | Tenant-scoped RBAC | Alice edits documents in Acme and reads documents in Globex. |
| Access depends on a relationship to one object | OpenFGA | Bob views a document shared with his team. |
| A relationship depends on expiry or another attribute | OpenFGA conditions | A document share lasts for 30 days. |
| Access depends on attributes of the user or resource | Cedar | Owners edit their own documents unless they are confidential. |
| A backend check needs trusted request facts | Cedar request context | Approving a document requires MFA. |
| A deny must override grants from several models | Combine model decisions | Block a suspended user even if a role or share grants access. |
| You want rules as policy text that people can review | Cedar | A security team reviews a policy file. |
Start with roles, add sharing when needed
Section titled “Start with roles, add sharing when needed”RBAC is the shortest path when roles describe your access rules. Use permissions.rbac to manage roles, permissions, and assignments. A user can hold a role app-wide or in one scope. Those assignments are separate: an app-wide role does not automatically apply within a tenant.
Use permissions.fga to manage authorization models and relationship tuples. Use it for individual shares, nested teams, and access inherited from folders. Conditions are part of this model and use a CEL expression on a tuple.
Use permissions.cedar to manage policies and entities. Policies permit or forbid actions on resources, with conditions on attributes or trusted request context. Use it for rules expressed as policy text, including attribute checks, nested groups and explicit denies. A Cedar forbid overrides every matching permit in Cedar.
Request context is available to the admin check. The current-subject functions accept no request context; they use stored entities and can receive resource attributes from your backend or an RLS policy. See Check access.
The three models have separate data and APIs. A role does not create a relationship, a relationship does not assign a role, and a Cedar policy does not read either. Your backend can combine their results into one decision. For example, allow a role or a share to grant access, while requiring a suspension check to pass.
To add sharing to an existing RBAC application, keep the roles and add OpenFGA tuples and checks. If you enforce table access with RLS, Combine models with RLS shows separate policies for each model and a restrictive policy for a deny across them. Keeping those grant policies separate can improve query performance.
How the models compare
Section titled “How the models compare”| RBAC | OpenFGA | Cedar | |
|---|---|---|---|
| You write | Roles, permissions, assignments | An authorization model, and tuples | Policies, and entities |
| A rule is | A role has a permission in a scope | A relationship between a user and an object | A permit or a forbid with conditions |
| Attributes | No | On a relationship, with CEL conditions | On entities, on the resource and in the context |
| Deny behavior | No explicit deny; a missing grant returns false | but not excludes access through that relation |
forbid overrides Cedar permits |
| Groups | Role inheritance | Teams and nested teams | Any hierarchy of entities |
| JavaScript check for the current user | rbac.hasPermission() |
fga.check() |
cedar.isAuthorized() |
| List accessible scopes or resources | rbac.scopesWithPermission() |
fga.listObjects() |
cedar.listResources() |
| How you represent a share | A role assignment in an object scope | A tuple | Entity data used by a policy, or a template link |
Denies within OpenFGA or Cedar do not automatically override another model’s answer. Apply a deny across models in your backend’s combined decision, or use a restrictive policy if you choose RLS.
Choose where to enforce access
Section titled “Choose where to enforce access”Check access in your application covers backend enforcement with SQL or JavaScript. Use it to authorize API requests, server functions or other operations. The backend handles the result before carrying out the operation.
RLS policies are an optional way to enforce access on database rows. They can call the model functions and add conditions on row columns, such as allowing only editors to see drafts. A Cedar policy defines a rule in the Cedar language; it works with either enforcement approach and does not require an RLS policy.
Other models
Section titled “Other models”ABAC describes a category of authorization rules. Use Cedar for attributes of the user, the resource and the request, and OpenFGA conditions for attributes on a relationship. Your backend can supply trusted resource attributes; an RLS policy can supply them from a row. CEL support here is part of OpenFGA conditions, not a separate authorization model.