Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

Designing a role model

All names, domains, and identifiers in these examples are fictional. The Gazette's five roles did not come from nowhere, and they were not Theo's first attempt. When Theo first set up roles, the obvious place to start was the newsroom's organization chart, and the first draft had a role for every title on it.

Starting from tasks

That draft had roles called Chief photographer, Staff photographer, Photo intern, Deputy picture editor, Picture editor and Night editor. It looked complete and was hard to use. Titles describe seniority and reporting lines, not what someone does in the library. The chief photographer and a staff photographer upload and caption in exactly the same way. A night editor approves pictures like any picture editor, just later in the day. Meanwhile one title could hide very different work: one staff photographer also ran the desk's social media accounts and needed to share albums, while the others did not. Every promotion became an access change, even when nothing about the person's work had changed.

The version the Gazette kept started from the tasks people perform in the library, the same list its permissions were drawn from, and grouped the tasks that the same people always do together. Finding pictures for a story is one cluster. Supplying pictures from an assignment is another. Choosing, captioning and approving a desk's pictures is a third, and placing legal holds and managing access are separate again. Each cluster became a role that can be described in one sentence about work: a Contributor supplies pictures, and a Picture editor runs a desk's pictures.

One question helps when a role seems to fit two groups of people. If the people holding it would ask for different permissions, it is really two roles. If they need the same permissions in different places, it is one role assigned in different scopes. Sports and news picture editors do the same work in different libraries, so the Gazette has one Picture editor role, assigned in two scopes. Designing and maintaining roles, in the governance lessons, compares this way of finding roles with mining them from the access people already hold.

Built-in and custom roles

The five roles the library starts with are built-in roles, defined by the photo service itself. They cover needs that nearly every newsroom shares, they mean the same thing in every organization that uses the service, and the service's developers keep them up to date as new permissions are added.

Sooner or later an organization needs something the built-in roles do not offer. The Gazette's rights desk manages licensing agreements with agencies and freelancers, and it needs to correct license terms and photographer credits. No built-in role includes photo.edit_rights. The closest, Picture editor, would also let the rights desk approve and delete photos, which is exactly the overgranting the permissions were designed to avoid. So Theo creates a custom role:

{
  "id": "rights-editor",
  "name": "Rights editor",
  "description": "Corrects license terms and photographer credits.",
  "permissions": ["photo.view", "photo.edit_rights"]
}

A custom role is composed by the organization from permissions the service already has, and once assigned it works exactly like a built-in one. Each desk can compose roles for its own needs in the same way. The sports desk, for example, later builds one for its desk lead.

What a custom role cannot do is invent a permission. If Theo could type photo.watermark into the Rights editor role, the library would accept a role that sounds meaningful and does nothing, because no route anywhere asks can(user, 'photo.watermark', photo). A near miss is worse. A role containing photo.edit_right, one letter short, looks right to anyone skimming it and grants nothing, and the rights desk would find out only when its first correction was refused. So the library accepts only names from its permission catalog when a role is created or changed, and rejects anything else.

A new capability therefore starts in code. A route begins checking a new permission, and the catalog gains its name. Only then can roles include it, and someone has to decide deliberately which built-in roles, if any, receive it, rather than letting the new power land wherever it happens to.

Inheriting permissions

The built-in roles repeat one another. Every role includes photo.view, and Picture editor contains all of Contributor. A role hierarchy removes the repetition by letting one role inherit from another:

Viewer                 photo.view
Contributor            inherits Viewer
                       adds photo.upload, photo.edit_caption
Picture editor         inherits Contributor
                       adds photo.download, photo.approve, photo.delete,
                            album.create, album.share
Legal reviewer         inherits Viewer
                       adds photo.place_hold
Library administrator  inherits Viewer
                       adds role.edit, role.assign

The definitions are shorter, and the effective permissions are exactly the same as before. The difference appears when someone changes a role that others inherit from. The Gazette's web team holds Viewer, and they ask to download approved photos for the website. The request is reasonable. The person handling it opens Viewer, sees a single permission, and adds photo.download.

That change did not land only on the web team. Contributor inherits from Viewer, so every Contributor can now download full-resolution files. Lena can download every unpublished photo in the festival album. Legal reviewers and the library administrator gained it too. Nobody decided any of that. The person editing Viewer saw one role with one permission, and the change took effect in four roles. It also gave the web team more than they asked for, because photo.download covers every photo they can see, not only approved ones.

A hierarchy is safest when it is shallow and when every edit shows its full reach before it is saved: a change to Viewer should list Contributor, Legal reviewer and Library administrator as affected. Often the better answer is to leave the shared role alone. A small Web editor role holding photo.view and photo.download, assigned to the web team, gives them what they asked for and nobody else anything.

When roles multiply

Custom roles make it easy to answer each new request with a new role, and over a year the Gazette's list grew. After a phone was lost at a match, the sports desk wanted picture editors who could download unpublished photos only on newsroom laptops. Freelancers on sports assignments needed less than staff photographers. Some wire photos were licensed only for certain countries, and the contributors who handled them needed roles limited to those photos. Each request produced a role, and then a sports and a news version of it:

Role someone createdWhat would replace it
Sports picture editor, News picture editorOne Picture editor role, assigned in each library's scope
Picture editor on managed devicesWhether the request comes from a newsroom-managed device, environment.device.managed
Freelance sports contributorThe person's employment type, subject.employment, set to freelance
Freelance sports contributor for region-licensed wire photosEmployment type, plus the regions a photo is licensed for, resource.license_regions
Embargo-cleared picture editorThe photo's release time compared with the current time, resource.embargo_until and environment.time

Every new condition multiplies the list. Two desks, two employment types, three license regions and managed or unmanaged devices already make 24 versions of a single role, and one more region adds eight more. This is role explosion, and its signs are easy to recognize: role names containing "only", "for" or "on", roles that differ from one another by a single condition, and roles that nobody can explain without digging through their history.

Those roles were not describing new kinds of work. They were describing conditions on the person, the photo and the situation, and copying the same work into every combination. Conditions like these can be written once, as rules about attributes, instead. The next group of lessons, starting with Writing rules with attributes, rewrites the Gazette's growing list that way.

Keeping access small

Least privilege is easy to apply on the day access is granted. The harder part is that access tends to grow afterward. When Omar takes two weeks off, Maya covers the sports picture desk and is assigned Picture editor in the Sports library. If nobody remembers to remove that assignment, Maya can still approve and delete sports photos a year later. If Maya later moves to the news desk, Maya will need Contributor in the News library, and the sports assignments will stay unless someone is asked to remove them. Each grant is reasonable on the day it is made. Their sum is not. This slow accumulation is called role creep, and it is the normal result of a model in which access is only ever added.

Some access has a natural end, and the assignment can record it. Lena's exists for the festival, so it can expire with the festival:

{
  "principal": { "type": "user", "id": "user-2290" },
  "role": "contributor",
  "scope": { "type": "album", "id": "4410" },
  "granted_by": "user-1002",
  "granted_at": "2026-06-08T09:30:00Z",
  "expires_at": "2026-06-30T23:59:59Z",
  "reason": "Riverside festival assignment"
}

Once the expiry passes, the assignment stops applying on the next request, whether or not anyone remembers it. Maya's two weeks of cover can be granted the same way. Not everything has an end date, since a staff photographer's desk has none, but wherever access is meant to be temporary, an assignment that ends by itself is more dependable than a reminder to remove it. The reason field helps whoever looks at the assignment later to understand why it existed.

Access without an end date still needs someone to look at it from time to time. Noticing that a desk assignment outlived a move, confirming that each group's members still belong in it, and removing access when people leave are how organizations keep least privilege true over time. Changing jobs and Access reviews, in the governance lessons, cover how they do it.

Try it in the Lab

PUT IT INTO PRACTICE

Check your understanding

Try these questions before moving on. If an answer isn't right, use the feedback and try again.

0 of 2 answered correctly

Enable JavaScript to answer these questions and save progress in this browser.

QUESTION 1 OF 2The Gazette has Sports picture editor, News picture editor and a managed-device version of each, and plans to add versions for wire photos licensed only in certain countries. What does this pattern suggest?

QUESTION 2 OF 2Contributor inherits from Viewer. The web team holds Viewer and needs to download approved photos, so someone adds photo.download to Viewer. Who gains it?

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

Learn identity