RBAC vs ABAC: Authorization Patterns for Multi-Tenant SaaS

A door lock whose fixed brass keyway is being replaced by a programmable policy dial, encoding RBAC versus ABAC

TL;DR

  • RBAC vs ABAC is not a versus: start with roles, add attributes and policies only when roles alone force you into role explosion.
  • RBAC is enough when access follows a small, stable set of tenant roles like admin, editor, and viewer.
  • ABAC becomes necessary for per-tenant custom roles, row-level and field-level rules, and context like time, region, or compliance tier.
  • Role explosion is the tell: when your role count climbs into the hundreds to encode combinations, you have outgrown pure RBAC.
  • Authorization bolted on late is one of the most painful retrofits we see, because permission checks end up scattered across every endpoint.

For a multi-tenant SaaS product, the honest answer is: start with RBAC, and reach for ABAC when roles alone stop describing the access rules your customers actually ask for. RBAC (role-based access control) assigns permissions to named roles like admin or viewer. ABAC (attribute-based access control) evaluates attributes of the user, the resource, and the request context against written policy. Most products need both, in that order.

We get pulled into this decision most often when it has already gone wrong. A product shipped with a handful of hardcoded roles, then enterprise customers arrived asking for their own custom roles, region-scoped access, and field-level redaction. The team is now threading if (user.role === 'admin') checks through hundreds of endpoints, and every new tenant requirement forks the logic again. Authorization retrofitted late is one of the more expensive rescues we do, and it is worth getting the model right early.

The difference between RBAC and ABAC

RBAC answers “who is this user?” ABAC answers “under what conditions does this specific request make sense?” RBAC groups permissions into roles and assigns roles to users. ABAC writes rules over attributes, so access can depend on the resource owner, the tenant’s plan, the time of day, or a data classification, without inventing a new role for each combination.

The NIST SP 800-162 guide defines ABAC as authorization determined by evaluating attributes of the subject, object, operation, and environment against policy. That environment clause is the whole point: RBAC has no natural place to put “only during business hours” or “only for records in the user’s own region.”

Dimension RBAC ABAC
Unit of decision Named role Attribute rule / policy
Granularity Coarse (per role) Fine (row, field, context)
Multi-tenant fit Good for stable roles Needed for per-tenant custom rules
Role explosion risk High as combinations grow Low (no roles to multiply)
Reasoning about access Easy to read and audit Harder without tooling
Change cost New role per new case Edit policy, no schema churn

When RBAC is enough for a multi-tenant SaaS

RBAC is enough when access maps cleanly to a small, stable set of roles that mean the same thing in every tenant. If admin, member, and viewer cover your permission needs, roles are simpler to reason about, cheaper to audit, and easier for customers to understand. Do not add a policy engine to a product that does not yet need one.

Signs RBAC still fits:

  • Roles are consistent across tenants and rarely change.
  • Permissions are per-feature, not per-row or per-field.
  • You are not encoding time, location, or data-sensitivity rules.
  • Compliance asks for “who can do what,” not “under what conditions.”

One caveat that trips teams up: even pure RBAC in multi-tenancy needs a tenant boundary underneath it. A role is always scoped to a tenant, so “admin” means admin of this workspace, never global. That tenant scoping is architectural, and it belongs in the same conversation as your shared-versus-isolated multi-tenant architecture decision, not bolted on after.

Decision flow for choosing RBAC or ABAC in a multi-tenant SaaS product

When ABAC becomes necessary

ABAC earns its place when roles alone can no longer express the rules without multiplying. The trigger is almost always one of four demands: per-tenant custom roles, row-level access, field-level redaction, or context-dependent rules. Each of these forces RBAC to encode a new combination as a new role, and that is where the model breaks down.

Per-tenant custom roles

The moment one enterprise customer wants a “regional auditor” role that no other tenant has, a single shared role catalogue stops working. You either fork roles per tenant (unmaintainable) or move the varying part into attributes and policy.

Row-level and field-level rules

“Sales reps see only their own accounts” is a row-level rule. “Support can see the ticket but not the customer’s tax ID” is a field-level rule. Neither is a role. Both are attribute comparisons between the user and the specific record, which is exactly what ABAC is built to evaluate.

Compliance and context

Regulated tenants often need access tied to region, clearance, time window, or data classification. These are environment conditions, and we have written before about how compliance shapes system design in designing systems that survive a compliance audit. RBAC has nowhere to put them; ABAC treats them as first-class inputs.

Role explosion, and how to spot it early

Role explosion is when an RBAC system accumulates so many roles that the permission structure becomes unmanageable. It happens because RBAC encodes every access requirement into a role name, so each new combination of scope, region, or resform spawns another role. In large deployments the count climbs into the hundreds or thousands, and nobody can say with confidence what any given role actually grants.

Key numbers behind multi-tenant authorization models

The pattern is the same one we see with other architectural shortcuts that compound quietly, much like the way teams accumulate technical debt without realising it. If you are creating roles like editor-eu-readonly-nopii, the role name is doing the job attributes should be doing. That is the signal to stop adding roles and add a policy layer instead.

What a hybrid RBAC plus ABAC model looks like

Most mature multi-tenant products land on a hybrid: RBAC for the coarse “what job does this person do,” ABAC for the fine “does this specific request satisfy the rules.” You keep roles because they are readable and easy to audit, and you push the conditional, per-tenant, per-row logic into policy. AWS documents exactly this pattern in its prescriptive guidance for multi-tenant RBAC and ABAC.

Where relationships drive access (folders, projects, shared documents, org hierarchies), a third model helps: ReBAC, or relationship-based access control, popularised by Google’s Zanzibar paper and its open-source descendants. A policy engine is what ties these together. Rather than scatter checks through the code, you centralise the decision:

  • OPA / Rego for general-purpose, declarative policy across services.
  • AWS Cedar for auditable RBAC and ABAC with a purpose-built language.
  • Oso and OpenFGA for application and relationship-based authorization.

The one hard rule: separate the authorization decision from the business logic. When the check lives in one place, adding a new tenant rule is a policy edit, not a hunt through every endpoint. That separation is the single most important architectural decision here, and like most decisions that are hard to reverse, it costs far less to make early than to retrofit.

How AlterSquare approaches this on a rescue

When we inherit a product with authorization sprawl, we do not rip out RBAC and swap in a policy engine overnight. We map where every permission decision currently lives, usually the output of a first-week legacy audit, then extract those checks into one authorization layer without changing behaviour. Only after the decision point is centralised do we start moving the volatile, per-tenant rules into attributes and policy. This ties directly into the broader security requirements every serious platform must meet, because access control that nobody can audit is a security gap, not just a design smell. Get the model right while the product is small, and it stays a configuration problem instead of becoming a rewrite.

Frequently Asked Questions

Is ABAC always better than RBAC?

No. ABAC is more flexible but harder to reason about and audit. If your access rules map cleanly to a small, stable set of roles, RBAC is simpler and safer. ABAC only pays off once roles alone force you into role explosion or cannot express row-level, field-level, or context-based rules.

Can you use RBAC and ABAC together?

Yes, and most mature multi-tenant SaaS products do. The common pattern is RBAC for coarse role assignment and ABAC for fine-grained, conditional, or per-tenant rules layered on top. AWS and most policy engines explicitly support this hybrid model with a single shared policy store.

What is the difference between ABAC and ReBAC?

ABAC decides access by comparing attributes of the user, resource, and environment against policy. ReBAC (relationship-based access control) decides based on relationships, such as membership in a group or ownership of a document. ReBAC, popularised by Google’s Zanzibar, fits products where sharing and hierarchy drive access.

Do I need a policy engine like OPA or Cedar?

Not on day one. A small product with stable roles can enforce RBAC in application code. You need a policy engine once authorization logic is complex enough that scattering checks across endpoints becomes unmaintainable. Engines like OPA, Cedar, Oso, and OpenFGA centralise the decision so rules live in one auditable place.

Why is authorization so hard to add later?

Because permission checks tend to spread through every endpoint and query as a product grows. Retrofitting means finding and rewriting each one without changing behaviour, then centralising them, all on a live system. Designing a single authorization decision point early keeps it a configuration change instead of a rewrite.

Huzefa Motiwala is a co-founder of AlterSquare, an application-layer partner that helps SaaS and tech-led companies stabilise, modernise, and extend complex systems without breaking what already works. He comes at software from design and frontend, with a focus on data-heavy interfaces and on getting real teams to actually adopt what gets built — not just ship it. He writes about working in fragile, high-stakes codebases: incremental change over risky rewrites, UX and technical debt, and embedding AI into real workflows.

Leave a Reply

Your email address will not be published. Required fields are marked *