
Guide
Access Control
Role-based access control: how RBAC works, where it breaks, and what to add
Guillaume Rigal
RBAC was designed for a world where the caller has a job title. Most of them still do. Some of them are now agents. Here is what still works and what has to change.
Role-based access control, or RBAC, is the default way to manage access. It is popular because it matches how companies already think: people do jobs, jobs come with a set of things you are allowed to do, so you name the set and hand it out. Almost every operational backoffice runs on RBAC, including the ones whose teams would never use the acronym.
But companies hit the limits of RBAC as they expand. The list of roles becomes as long as the company roster. Half of those roles differ by a single permission, and nobody can say with confidence which ones matter or who should hold them. Add AI agents on top of that, and you have to decide whether they deserve a human role or need guardrails of their own.
We start with RBAC as it works today: its three pieces, how it compares to the alternatives, and why role explosion is predictable. Then we look at what changes when the caller is an AI agent or an automation, which is a smaller change than the noise suggests and a more specific one than most advice admits.
What is role-based access control?
Role-based access control is a model where permissions are grouped into named roles, and roles are assigned to people. Nobody holds a permission directly. They hold a role, and the role holds the permissions.
Three pieces, and the whole model is the relationships between them.
Piece | What it is | Example |
|---|---|---|
Permission | One action on one kind of object | Update a dispute |
Role | A named bundle of permissions | Disputes Analyst |
Assignment | The link between a person and a role, usually through a team or group | Everyone in the Disputes team holds Disputes Analyst |
The value is in the indirection. When the disputes process changes, you change one role and forty people move with it. When somebody joins, you assign a role rather than reconstructing what they need from memory. And when somebody asks what a job is allowed to do, there is a single named thing to point at.
That last one is why RBAC survives models that are technically better. It is the only common model where "what can this person do?" has a short answer: the name of their role.
Why RBAC became the default
RBAC spread for two practical reasons.
It maps to the org chart. Non-engineers can read it. An operations lead can look at a list of roles and say whether it is right, which is not true of a policy engine. A control that nobody outside engineering can audit is a control that does not get audited.
It is cheap to check. Deciding whether somebody may act is a lookup rather than an evaluation. That matters less than it used to at the volume an internal tool runs at, but it is why RBAC arrived first and why every other model still gets bolted onto it.
RBAC vs ABAC vs ReBAC vs ACL: which should you use?
For almost every operational backoffice, RBAC works as the foundation, and some setups require an additional model for the cases RBAC cannot express. The question is which one, and the answer comes from what your exceptions actually depend on.
Model | Access is decided by | Choose it when | It breaks when | Pair it with |
|---|---|---|---|---|
ACL (access control list) | A list attached to each individual object | You have few objects and sharing is explicit and personal | Volume. A thousand users and ten thousand records is ten million possible entries | Nothing. At any real scale, what you needed was ReBAC |
RBAC (role-based access control) | The role the person holds | Access follows the job, which is almost always | Exceptions multiply and roles start describing situations instead of jobs | ABAC for conditions, ReBAC for ownership |
ABAC (attribute-based access control) | Attributes evaluated at the moment of the request: who, what, when, how much | Your rules genuinely depend on context. Amount thresholds, time windows, location | Nobody can answer "what can Marie see?" without running the engine and reading the result | RBAC underneath, so somebody can still answer the question without running the engine |
ReBAC (relationship-based access control) | The relationships between people and records | Access follows assignment or ownership. This case is mine, so I can see it | The relationship data goes stale and access silently follows it | RBAC underneath, for everything not case-based |
Pairing is the key notion in that table. ACL, ABAC and ReBAC rarely work in isolation: ACL does not survive volume, ABAC becomes unauditable on its own, and ReBAC only covers access that follows a relationship. RBAC is the foundation almost every operational backoffice actually runs on, so the real decision is which second model you add to it.
Choose that second model from your last ten exception requests. If they depended on an amount or a time, you need ABAC. If they depended on who the case belonged to, you need ReBAC. If they were genuinely one-off, you do not have a model problem, you have a role problem, and the next section covers it.
Role explosion is the failure mode, and it is predictable
Somebody needs an exception. Creating a new role is a five-minute job and nobody has to think about it, so a new role gets created. Now there are two roles that are almost the same. Six months later there are nine, with names like Support EU Tier 2 Escalations and Support EU Tier 2 Escalations Temp, and nobody can say which of them anybody should have.
The usual tell is when a role name describes a situation rather than a job. "Disputes Analyst" is a job. "Disputes Analyst Without Refund" is a situation somebody encountered on a Tuesday.
Four practices prevent role explosion:
Name roles after operations, not org units. Roles built from the verbs your business performs stay true when the org chart changes. Roles named after teams need renaming every reorg, and renaming is how they multiply.
Use scopes for the "which records" exceptions. Most new roles are not asking for a different set of permissions. They are asking for the same permissions over fewer records. That is a scope, and one role with a scope replaces five near-identical roles. In Forest a scope is attached to the collection and resolved against whoever is logged in, so a single Disputes Analyst role serves every market without a variant per region.
Put a limit on the count and defend it. Not because the number is meaningful, but because the friction is. If adding a role requires deleting one, somebody has to think.
Delete the temporary ones. Every temporary role needs an end date at the moment it is created, or it is permanent and everyone is pretending otherwise.
Underneath all four is one decision: design permissions around what the business does, not around who does it. Job titles change within a quarter. "Issue a refund" does not.
Where does RBAC stop working?
RBAC stops being sufficient in three situations. Two of them predate AI agents and most teams have already met at least one. The third is new, and it is what the rest of this guide is about.
Cross-tenant access. RBAC assumes one organization. The moment a partner, a business process outsourcer or your own customer touches your data, roles are the wrong instrument, because the question is not what this person does but whose data they may touch. That needs isolation as a separate mechanism, sitting underneath roles rather than beside them, and it is covered in permissions beyond your own team.
Time-bound access. RBAC has no concept of expiry. Somebody needs elevated access for one incident, gets a role, and holds it forever, because removing it requires somebody to remember. Every RBAC system in production has at least one of these, and finding them is what an access review is for.
Callers that are not people. This is the new one, and it is the rest of this article.
What does a role look like when an AI agent holds it?
An AI agent has no job title. It has a task, and whoever asked for it. That single fact decides most of what follows, because a role is a description of a job, and here there is no job to describe.
Which is why the answer, most of the time, is not to build one:
When a person asked for the work, the agent inherits their role. A disputes analyst asks their assistant to pull every case older than five days. The agent authenticates as that analyst and holds Disputes Analyst because they do. No role was created, nothing new has to be reviewed, and when their role changes the agent's reach changes with it. This is how Forest handles it: an agent signs in as a user and holds that user's role, and there is deliberately no separate role type for agents.
When nobody asked, the automation needs a role of its own. A nightly re-screening job has no person behind it. That one gets a role, and the role should be built the way any good role is built: from the operations it actually performs, deny by default, scoped to the records it needs. How it then signs in, and why a shared API key is not an identity, is in our guide to user authentication.
The mistake to avoid is minting an "AI Agent" role, which is a role named after a technology rather than a job or an operation. It will accumulate permissions from every team that wants to automate something, and within two quarters it is the widest role in the system with no owner.
One practical note on agent roles: they are usually narrower than a person's, and they should be. A person's role includes everything they might need on a bad day. An automation does one thing. Build the role for the thing, and resist the temptation to reuse the human role because it is already there.
How the two paths look in Forest. Both use the objects you already have, and neither introduces a new kind of role.
The agent acts as a person | The agent acts as itself | |
|---|---|---|
What you create | Nothing. It signs in as an existing user, by OAuth or an application token | A service account |
The role it holds | That user's role, through their team | Its own role, through its own team |
When you change that role | The agent's reach changes with it, in one place | Only that automation is affected |
The activity log shows | The person's name | The service account's name |
Narrowing it further | Point the agent at a second account with a narrower role | Edit its role, like any other |
There is deliberately no third option and no role type reserved for agents. That is the design decision worth copying whether or not you use Forest. An agent is a caller, and callers get roles the way callers already get roles.
Frequently asked questions about role-based access control
What is the difference between RBAC and ABAC?
RBAC decides from the role somebody holds. ABAC decides from the specifics of the request: the amount, the time, the record, the person asking. RBAC is readable and coarse. ABAC is precise and hard to audit. Most real systems run RBAC as the base and use ABAC for the handful of rules that genuinely depend on context.
How many roles should a company have?
Fewer than you have. There is no correct number, but if you have more roles than teams, the roles have started describing situations rather than jobs, and consolidation is overdue.
Is RBAC enough for compliance?
For most audits, yes, provided you can export the current state and show evidence that somebody reviews it. Auditors ask for readability and evidence far more often than they ask for sophistication.
Roles still work, but AI agents need specific attention
RBAC is not the thing that breaks when agents arrive. What breaks is the assumption sitting underneath it, that every caller has a job title somebody can look up.
So keep the roles. Build them from operations rather than org units, use scopes instead of near-duplicates, and let an agent inherit a person's role wherever a person actually asked. Create a new role only when nothing human is behind the call, and give that one an owner and a review date, because nobody will notice it otherwise.
The cost of all this is upkeep, and upkeep is what nobody budgets for. It is worth asking whether maintaining a role engine should be your job at all. Forest ships one on top of the databases you already have, and extends the same model to service accounts and to agents arriving through Forest's MCP Server, so there is one role list to review rather than three.
We have a wider guide on user roles and permissions. It covers how a role differs from a permission level, and why the two should never sit on the same ladder.
More questions about role-based access control
How do you implement RBAC?
Four steps, and the first one decides whether the rest holds.
List the operations your business performs, not the job titles it has. Refund, close, escalate, export, re-screen.
Group those operations into roles that match how the work is actually divided. If a role does not correspond to something somebody does all day, it is an exception in disguise.
Assign roles through teams or groups, never to individuals by hand. A role attached directly to a person is an exception nobody will find later.
Enforce at the data layer, not in the interface. A role checked only by the front end is a suggestion.
After that it becomes a maintenance job rather than an implementation one, which is covered in our guide to permission management.
Should roles inherit from each other?
You can, and it is worth resisting at first. Inheritance looks attractive because it removes duplication: Senior Analyst inherits everything Analyst has, plus two permissions. The cost arrives at the review, when answering "what can this person do" means walking a tree instead of reading a row.
If you do use inheritance, keep it to a single level, and never let a child role remove a permission its parent grants. A hierarchy where permissions are both added and subtracted becomes unreadable within a year.
Does RBAC scale to a large application?
The checking scales fine. Deciding whether somebody may act is a lookup, and it stays cheap at any volume you are likely to reach.
What does not scale is the human side. A hundred roles is not slow, it is unreadable, and an unreadable model is one nobody reviews. So the limit you hit is comprehension rather than performance, which is why the practices that keep the role count down matter more than any optimization.
