← Back

Essay

Your role model is a tree. Your company is not.

Two failures, in a fixed order: the hierarchy cannot express a role with two parents, and then the grant that actually matters turns out to be a slice rather than a role. The second one is how authorization ends up in application code.

Manah Khalil/

Every authorization system starts the same way and fails the same way twice.

Failure one: the second parent

You model roles as a hierarchy, because hierarchies are how people describe organisations out loud. Then a role arrives that belongs to two of them. A regional manager who needs the operations grants and the analytics grants.

A tree cannot say that. So you pick a parent and duplicate the other branch, and now there are two definitions of the analytics grants that are identical today. In eight months somebody adds a permission to one of them. Nobody notices, because nothing breaks: a person who should have access does not, and they work around it, and the workaround becomes how that team does it.

The fix is not complicated. A role should be able to have several parents. It is a graph, not a tree. Most products in this space describe a hierarchy and implement a tree, and the way to find out which you have bought is to try to add the second parent in a trial.

Failure two: the grant is a slice

This one is more expensive, and it is the one that actually decides where your authorization logic lives.

The role is almost never the grant. What people need is not "manager", it is "manager of these locations". Not "buyer", but "buyer in these categories". Not "clinician", but "clinician at these sites". The thing being granted has a shape, and the shape is a slice through one or more dimensions.

Watch what happens when the model cannot hold that. In order of how bad each one is:

  1. It goes in the role name. manager-tx, manager-ca, manager-tx-produce. This works for a while and then combines. Two regions and two categories is four roles. Six regions and eight categories is forty-eight, and somebody is maintaining them in a spreadsheet.
  2. It goes in a claim as a string, and every application parses it. Now the parsing is duplicated per application and per language, and two of them disagree about whether the list is comma-separated or space-separated.
  3. It goes in a table in the application, with a join. This one feels clean, and it is the most damaging, because from that moment the answer to "who has access to what" is distributed across every application you own. There is no query that answers it. There is only asking each team, and each team is confident, and two of them are wrong.

By the time you are at option three you have built an authorization system. You did not plan to. You have not tested it as one. Nobody owns it.

What holding the slice properly looks like

A scope is a type and a value, attached to the assignment rather than to the role. And there is one rule for how they combine, which is the rule that makes the whole thing expressive enough to be worth having:

Values of the same type are alternatives. Values of different types combine.

So an assignment carrying region = TX, CA together with category = produce, dairy grants four things: Texas produce, Texas dairy, California produce, California dairy. One assignment, four grants, no role explosion and no string parsing.

That single rule is the difference between a model that expresses an organisation and a model that offloads it to your application developers. It is worth testing before you buy anything: assign a scoped role, then read the token. If the token carries the role name and the expansion is left to you, you are buying a directory and writing an authorization system.

Then compute it at the right time

One more thing, and it is where products that get the model right still lose.

Entitlements must be resolved when the token is issued, not cached and trusted. If the grant is baked into a long-lived token or a claim that refreshes hourly, then removing somebody's role does nothing for an hour, and "we revoked it" and "they no longer have access" are two different statements that everybody in the room will treat as one.

Resolve at issuance, keep tokens short, rotate refresh tokens, and revocation becomes a fact rather than an intention.

The uncomfortable part

Doing this properly means the model is capable of expressing a mess. A graph with cross-product scopes will describe your organisation faithfully, including the parts of it that nobody would defend in a meeting.

That is not an argument for a weaker model. It is an argument for looking at what you actually have, once, in one place, in a form you can read. Most organisations have never seen it, because it was never in one place to see.