Authorization is the question that comes right after sign-in: you know who the caller is, so what are they allowed to do? Authdog answers that on the server, once per environment, with one of three models. Pick the model that matches how your product thinks about access.
To set up roles in practice, see Roles and permissions.
Authentication vs authorization
Keep the two steps separate. Mixing them is how apps end up trusting "they're signed in" as if that meant "they can do this."
- Authentication establishes identity. The session proves who the caller is.
- Authorization makes a decision. Given that identity (and sometimes the resource and the context), is this action allowed?
A request is authenticated once. It can be authorized many times, once for each protected action.
Pick one model per environment
Each environment runs exactly one authorization model. One engine decides every request, so the answer is unambiguous. You can still use a lightweight model in one environment and a richer one in another, without rewriting your app.
| Model | Decides based on | Best when |
|---|---|---|
| RBAC | the roles a user holds | access maps cleanly to job functions |
| ABAC | attributes of the user, the resource, and the context | rules depend on data (department, ownership, time) |
| FGA | relationships between users and objects | access is per object and hierarchical (folders, docs, teams) |
RBAC: role-based access control
This is the default, and the right place to start. You define roles, grant each role a set of permissions, and assign roles to users. A user's effective permissions are the union of every role they hold.
You can assign a role directly, or grant it from an identity-provider or HRIS group through provisioning. Organization membership is separate: it governs who administers the account and its tenants, not end-user RBAC inside an environment.
role: editor permissions: [post.read, post.write]
role: admin permissions: [post.*, user.manage]
user jane -> [editor] => can post.read, post.writeRBAC is seat-based and easy to reason about. Stay here unless you already know you need more.
ABAC: attribute-based access control
Use this when access depends on data, not a fixed job title. A rule like "a manager can approve expenses under $5,000 in their own department" turns into a pile of roles if you try to express it with RBAC. ABAC evaluates a policy against attributes of the subject, the resource, and the request.
Authdog policies are written in Rego (the Open Policy Agent language) and evaluated at the edge, in process. There's no external policy server and no extra network hop. You author policies per environment, and they're versioned.
package authdog.authz
default allow = false
allow {
input.user.department == input.resource.department
input.action == "approve"
input.resource.amount < 5000
}FGA: fine-grained (relationship) authorization
Use this when permission follows a relationship, object by object. "Anyone who can view a folder can view every document inside it" is that kind of rule. Authdog gives you a Zanzibar-style model: you write relationship tuples (document:readme#viewer@user:jane) and a model that describes how relations inherit, then you ask check(user, relation, object).
tuple: folder:eng#viewer@user:jane
tuple: document:spec#parent@folder:eng
check(user:jane, viewer, document:spec) -> allowed (inherited via parent)You describe the model in an OpenFGA-style language, for example define viewer: [user] or viewer from parent. The console shows that model as a graph. See FGA and the console module.
FGA fits collaborative, document-centric products, where access is defined object by object.
How enforcement works
Whichever model the environment uses, the decision happens on the server, before your resolver or handler runs. The client can't skip it. The engine reads the caller's identity from the validated session, loads that environment's roles, policies, or tuples, and returns allow or deny. Any error fails closed. Tenant owners always keep management access.
Choosing a model
- Start with RBAC. Most apps never outgrow it.
- Move to ABAC when the decision depends on the resource or on context.
- Move to FGA when access is defined per object and inherited through a hierarchy.
You can run a different model in each environment, so it's safe to try a richer model in staging first.
Related
| Read | To learn how to |
|---|---|
| Roles and permissions | Set up RBAC in practice |
| AuthZEN API | Ask for a decision over a vendor-neutral contract |
| Organizations | Tell account membership apart from environment users |
| Provisioning | Grant roles from identity-provider or HRIS groups |
| Sessions and tokens | See the identity every decision starts from |