Roles, assignments, and scope
All names, domains, and identifiers in these examples are fictional. The Gazette's library now has twelve permissions and about forty people who need some of them. Granting permissions one at a time, person by person, would turn Theo's job into maintaining a grid of forty rows and twelve columns, where nobody could tell whether two picture editors had different access on purpose or by accident.
Grouping permissions into roles
A role is a named set of permissions that describes a kind of work. The Gazette's library comes with five:
| Role | Permissions | Who holds it in the newsroom |
|---|---|---|
| Viewer | photo.view | Reporters and others who look for pictures to go with stories |
| Contributor | photo.view, photo.upload, photo.edit_caption | Photographers, such as Maya and Lena |
| Picture editor | photo.view, photo.download, photo.upload, photo.edit_caption, photo.approve, photo.delete, album.create, album.share | Each desk's picture editors, such as Omar |
| Legal reviewer | photo.view, photo.place_hold | The legal team, including Raj |
| Library administrator | photo.view, role.edit, role.assign | Theo |
A role turns a decision about a person into a sentence anyone can read. Making someone a Contributor says what they will do in the library, and whoever reviews access later can understand it without comparing permission lists. When the Gazette changes what a role includes, everyone holding it changes together. This is where checking permissions, not titles, pays off: the approve route asks about photo.approve, and the roles decide who that covers.
One permission appears in no row. Nobody holds photo.edit_rights yet, because none of these kinds of work includes correcting license terms. Designing a role model returns to it.
A role on its own grants nothing. Picture editor could sit in the library for months without anyone being able to approve a single photo. It starts to mean something only when someone is assigned it, and an assignment has to say where.
Assigning a role somewhere
A role assignment has three parts: who receives the role, which role it is, and where it applies. The "who" is called the principal, a person or a group of people. The "where" is the scope: the whole organization, one library, or one album. The library stores each assignment as a record with all three. This is Lena's:
{
"principal": { "type": "user", "id": "user-2290" },
"role": "contributor",
"scope": { "type": "album", "id": "4410" },
"granted_by": "user-1002",
"granted_at": "2026-06-08T09:30:00Z"
}
Theo, account user-1002, made Lena a Contributor on the Riverside festival album. Maya holds the same role, but in the Sports library, so Maya can upload to any sports album while Lena can upload only to the festival. The role and its permissions are identical. The reach is not. The scope is what lets the Gazette make Lena a contributor to one assignment without making Lena a contributor to the Gazette.
Scope is also the part most easily left out. The library's first role system stored a list of role names on each account, such as roles: ['picture-editor'], with no scope, because at the time the library held only the sports desk's pictures. Then the news desk moved its pictures in. Overnight, every sports picture editor could approve, download and delete news photos. Nobody had granted that. The assignments had never said where they applied, so they applied everywhere, and "editor" had quietly become "editor of everything".
The repair is to make scope a required part of every assignment rather than an optional detail. Access to the whole organization is still possible, but as a scope someone chose deliberately and that shows up whenever anyone reviews it, not as what happens when a field is left empty. Theo's Library administrator assignment is one of the few with that scope.
Groups and roles
Omar's access to sports photos does not come from an assignment made to Omar. It comes through a group. A group is a collection of people, such as Sports desk editors, while a role is a collection of permissions. The two are easy to confuse, because people are "put in" both, and some administration screens list them side by side. They answer different questions. A group says who belongs together. A role says what a kind of work needs.
A role can be assigned to a group, just as to a person. The Gazette assigns Picture editor in the Sports library to the group Sports desk editors, and membership then carries the assignment. When a new picture editor joins the sports desk, adding them to the group is all it takes, and when someone leaves the desk, removing them from the group removes the access. Theo maintains one assignment instead of one for every editor.
That convenience moves power to whoever manages the group. If its members come from the newsroom's staff directory, then anyone who can add people to Sports desk editors in that directory is, in effect, granting Picture editor in the Sports library, whether or not they think of it that way.
Nested groups make access harder still to see. Suppose Sports desk editors contains another group, Weekend desk, so that weekend staff can cover. Someone who later adds the interns to Weekend desk, perhaps to put them on its email list, has made every intern a picture editor. Answering "why can this person delete sports photos?" now means following a chain of memberships through groups that nobody ever looked at as access. Many organizations limit how deeply groups can nest for this reason, or show the whole chain wherever access is reviewed. Escalating privilege follows how an attacker can use a chain like this on purpose.
Working out effective permissions
A person's effective permissions for a resource are everything their assignments grant there. To work them out, the library collects every assignment that applies: each one made to the person, or to a group the person belongs to, whose scope is the resource itself or anything that contains it. A photo sits inside an album, the album inside a library, and the library inside the organization, so an assignment in the Sports library covers every album in it and every photo in those albums. The effective permissions are the union of the permissions of every role in those assignments.
The library's can function, from the lessons on permissions, relies on a helper that follows exactly these steps:
function grantedPermissions(user: User, resource: Resource): Set<string> {
// The resource and everything containing it: photo, album, library, organization.
const scopes = containingScopes(resource);
// The user and every group the user belongs to, including through nested groups.
const principals = [user.id, ...groupsOf(user)];
const roles = assignments.rolesFor(principals, scopes);
return new Set(roles.flatMap(role => role.permissions));
}
Take Omar and two photos. Photo 9001 is in the Riverside festival album in the Sports library. Photo 7310 is in album 5230 in the News library. Omar has the two assignments shown in the diagram:
| Assignment | For photo 9001 (Sports library) | For photo 7310 (News library) |
|---|---|---|
| Picture editor in the Sports library, through the group Sports desk editors | Applies: Omar is a member, and the photo's album is in the Sports library | Does not apply: the photo is outside the Sports library |
| Viewer in the News library, assigned to Omar directly | Does not apply: the photo is outside the News library | Applies: the photo's album is in the News library |
| Effective permissions | All eight Picture editor permissions, including photo.approve and photo.download | photo.view only |
So Omar may approve photo 9001 and may only look at photo 7310. If Omar asks to download 7310, no assignment that applies grants photo.download, and default deny refuses it. Assignments only ever add to one another. If Omar were also given Viewer for the whole organization, nothing would change for photo 9001: the broader Viewer assignment applies there too, but it cannot take away what the Sports library assignment grants.
Effective permissions are what the roles allow, which is not always the final answer. Picture editor includes photo.delete, but the Gazette never wants a photo under legal hold deleted, whoever asks. A rule like that depends on something about the photo rather than anyone's role, and Writing rules with attributes, later in this series, shows how such rules work alongside roles.