Authorization¶
Authentication decides who you are. Authorization decides what you can do.
Canonical page
This page is the canonical owner of roles, scopes, and the permission model. Other pages summarise it and link here; if a summary disagrees with this page, this page wins.
Four checks apply, in combination:
- Organization role. Are you a member of the organization, at a high enough level?
- Project role. Do you have the necessary access to this specific project?
- Token grants. If a token authenticated the request, do its scopes or its granted role cover the operation?
- Token binding. Does the organization or project the request addresses match the one the token is bound to?
Failing any of them produces HTTP 403 with permission_denied or
insufficient_role.
Organization roles¶
Every member of an organization holds exactly one role. They are cumulative: each includes everything below it.
| Role | Can |
|---|---|
| Read | See the organization, its projects, its members |
| Editor | The above, plus create and work in projects |
| Manager | The above, plus operate across every project in the organization, without needing a membership in each one |
| Admin | Everything, including members and invitations, billing, storage configuration, SSO, spend caps, audit, and deleting the organization |
Two things worth knowing:
- Manager is the "works everywhere" role. A Manager has full project-level access to every project in the organization without needing a per-project membership. That's why organization-wide operators don't have to be kept in sync with each new project. It is a project-scope fallback and nothing more: the organization's own membership is Admin work, so creating, listing, resending and revoking an invitation, changing a member's role, and removing a member are all refused for a Manager. Reading the member list is open to every member, and so is leaving the organization; nothing else on that list is.
- Admin is a superset, and it is also the ownership role. There is no separate owner: "transfer ownership" grants Admin to another member, an organization may hold several Admins, and each of them is a co-owner. See Organizations & members → Ownership.
Roles are set when you invite someone — an Admin action — and can be changed later from the organization's member list, also by an Admin. See Organizations & members.
Project roles¶
A project membership grants finer access than an organization role, and is how you give someone access to one project without giving them the organization.
| Role | Can |
|---|---|
| Read | See the project, its builds, channels, and releases |
| Read + Download | The above, plus download build artifacts |
| Read + Download + Upload | The above, plus upload builds and edit release notes |
| Maintainer | The above, plus manage channels and releases, hand out channel tester invitations, and change project settings |
| Admin | Full control of the project, including project-level tester grants and direct channel grants |
Read + Download + Upload is the role a build pipeline wants. Maintainer is the role a release manager wants.
Tester access splits across those last two rows, which surprises people: a Maintainer can invite someone to a channel, but adding a project tester, or listing and removing a direct channel grant, is Admin. Listing a channel's pending invitations stays with the Maintainer, because it is a read on the same Manage Testers role rather than a write. An organization Manager or Admin clears both without a project membership. See Managing testers → Who can grant what.
Project access tokens¶
A project access token is granted a project role, chosen from the table above, and bound to one project and its organization.
| Granted role | Typical use |
|---|---|
| Read | Read-only automation: list builds, read metadata |
| Read + Download | Mirror or archive artifacts |
| Read + Download + Upload | The canonical CI build pipeline |
| Maintainer | Automation that also manages channels, releases, or channel invitations |
| Admin | Full control of the project's build and release surface |
Two rules constrain what you can create:
- You cannot mint a token more privileged than you are. The granted role is capped at your own effective role in the project. A Maintainer cannot create an Admin token.
- A token is bound to one project. A request addressing a different project or organization is refused, so a leaked token is confined. If your pipeline pushes to several projects, create one token per project.
Creating one is itself Maintainer-gated, and so are rotating, revoking, and permanently deleting: an organization Manager or Admin satisfies that without a project membership, and a project member below Maintainer gets the same 404 every other project-access denial produces. Managing tokens also requires an interactive sign-in — no token, of either kind, can mint or manage another.
Personal access token scopes¶
A personal access token acts as you, bound to one organization, and carries a set of scopes:
| Scope | Lets the token |
|---|---|
| Read | Read metadata across the organization |
| Upload Build | Upload builds |
| Revoke Build | Revoke builds |
| Manage Releases | Create and manage channels and releases |
| Manage Testers | Create and revoke channel tester invitations |
| Edit Project | Change project settings |
Manage Testers is narrower than its name. It authorizes exactly two
operations: minting a channel tester invitation, and revoking one.
Everything else a reader would file under managing testers needs
ALL — adding an organization or project tester
grant, removing a grant at any of the three levels, re-notifying a
pending organization or project grant, and every tester-group write.
Reading a tester or invitation list is an ordinary Read-scope call.
A token carrying only Manage Testers can mint the invitation and take it
back; it cannot add or remove a grant.
Scopes intersect with your own permissions rather than adding to them. If either the scope or your role says no, the answer is no — demoting a developer immediately narrows every token they own.
You can only grant scopes you hold. The token creation screen offers exactly the scopes available to you in the chosen organization, so a combination the server would reject isn't offered in the first place.
A personal access token is bound to one organization. A request addressing a different organization is refused even if you belong to both. Create one token per organization.
The ALL scope¶
Above the six named scopes sits a single composite scope, ALL,
which is every present and future scope at once. On the wire it is the
single integer 9223372036854775807, and it is not the sum of
the six named bits: 1 + 2 + 4 + 8 + 16 + 32 is 63, which is only the
six scopes that exist today, while ALL is a sentinel that covers any
scope added later as well. It is not a convenience: a handful of
operations are unrecoverable, so they demand ALL rather than any
narrower bit, which stops a leaked single-purpose token from doing them.
Operations that require ALL include:
- Hard-deleting a build or deleting a project, both of which destroy audit-adjacent state permanently.
- Changing the organization's plan tier, because it changes how you are billed.
- Managing webhook subscriptions and sending test deliveries.
- Managing tester groups — every write, including creating a group, editing it, and moving members or grants in and out of it.
- Adding an organization or project tester grant, removing a grant at any of the three levels, and re-notifying a pending organization or project one. Only the two channel invitation operations — minting one and revoking it — drop to the narrower Manage Testers scope.
- Writing the monthly spend cap or the organization MFA policy.
Both are ordinary
ALL-scope writes: reading either back needs only Read. - Setting or removing the organization icon.
Two consequences worth planning around:
- Not everyone can mint it. The ceiling is the same as for every
other scope — you cannot grant what you do not hold — and for
ALLthat means an organization Manager or Admin, or an Admin on at least one project in the organization. A project Admin'sALLtoken is still bound to that one organization, and still intersects with their own permissions at use time. - The web app cannot create one. The token screen renders one
checkbox per named scope and
ALLis deliberately not among them, so anALL-scoped personal access token has to be created over the API.GET /api/v1/pats/grantable-scopesreflects this: it returns the per-scope boolean map with the composite deliberately absent, and a developer who may grant everything simply sees every entrytrue.
Prefer the narrow scopes. Reach for ALL only for the operations that
insist on it, and revoke that token when the job is done.
Route-level checks are the real contract
Individual operations declare the role and scope they require, and those declarations — not a summary table — are authoritative. The tables here describe the intent; the interactive reference describes each operation. When in doubt, grant the least you think will work and widen it if you get a 403.
Where tokens are refused entirely¶
Some operations require an interactive sign-in and reject long-lived
tokens whatever their scope — including ALL:
| Surface | Why |
|---|---|
| Account settings — the developer record, avatar, and email change | Changing who you are must require being you |
| Account security — MFA, TOTP, recovery codes, passkeys, sessions | Changing how you sign in must require signing in |
| Token management — creating, listing, rotating, revoking tokens, and reading grantable scopes | Otherwise a token could extend its own reach |
| Organization creation | A new billing boundary is a person's decision |
| SSO configuration — the connection, enablement, require-SSO, domains, SP metadata, and beginning SP-initiated Single Logout | It decides how everyone else signs in |
| Organization storage configuration, including BYOSA | Blast radius |
| Invitation acceptance — organization, project, and channel tester invitations | Accepting on someone's behalf is impersonation |
| Your own developer audit feed | Self-only, and the record of your own sign-ins |
These return HTTP 403, and the schema marks each of them. Sign in as a developer to perform them.
Three SSO endpoints are not on this list, because nothing has signed in by the time they are reached: the sign-in redirect, the assertion-consumer callback, and the Single Logout service the identity provider calls back on, where the SAML signature is the credential. Note the pair that share a name — beginning SP-initiated Single Logout is a signed-in call and is on the list above; the SLO service endpoint is not. See Authentication → Where long-lived tokens are refused.
Controls that exist only on the API¶
A few operations have no screen in the web app, so the API is the only way to reach them. None of them is a gate you can be talked past — the capability exists, the UI does not:
| Control | How to drive it | Who |
|---|---|---|
| Monthly spend cap | GET/PUT /api/v1/organizations/{organization_id}/spend-cap |
Organization Admin; the PUT also needs an ALL-scoped credential |
| Organization MFA policy | GET/PUT /api/v1/organizations/{organization_id}/mfa-policy |
Organization Admin; the PUT also needs an ALL-scoped credential |
| Organization-wide PAT inventory and revocation | GET /api/v1/pats/all, DELETE /api/v1/pats/{pat_id} |
Organization Admin, interactive sign-in |
| Plan tier change (Team ↔ Business) | POST /api/v1/organizations/{organization_id}/tier |
Organization Admin and an ALL-scoped credential |
Minting an ALL-scoped personal access token |
POST /api/v1/pats |
Organization Manager or Admin, or a project Admin; interactive sign-in |
The tier change is the one that surprises people: there is no plan
switcher anywhere in the web app, and unlike the account-security
surfaces above it does not insist on an interactive session — an
admin's ALL-scoped personal access token is accepted. See
Billing, usage & caps → Changing plans
and
Feature availability.
Testers¶
Testers hold grants, not roles. A grant attaches at one of three levels, and gives read-and-install access to the builds it covers:
| Grant | Reaches |
|---|---|
| Organization | Every channel in every project in the organization |
| Project | Every channel in that project |
| Channel | That channel only |
A tester can see and install what their grants cover, and nothing else: no audit feed, no member list, no other testers, no settings. See Managing testers & groups.
Tester groups are a convenience over the same model. A group holds members and holds grants; joining the group confers the grants.
Anonymous access¶
A channel can be made public, which mints a link that installs the channel's current release with no sign-in at all. That's the whole capability: no listing, no history, no metadata beyond what the install page shows. Turning the channel private revokes the link immediately.
Common 403s¶
error |
Cause |
|---|---|
permission_denied |
No membership, grant, or scope covers this action — or a token was used where an interactive session is required |
insufficient_role |
You're a member, but your role is too low |
email_not_verified |
The account hasn't verified its email address |
mfa_enrollment_required |
An organization you belong to requires MFA and you haven't enrolled |
None of these are fixed by retrying. See Errors.
Choosing roles well¶
- Default to the lowest role that works. It is easy to raise and awkward to un-leak.
- Use project memberships for contractors rather than organization roles.
- Use project access tokens for CI and personal access tokens for your own scripts.
- Testers should be testers. Don't hand out project Read to someone who only needs to install the app; that's what a tester grant is for.
- Review periodically. The member list, tester list, and token lists all show who has what.
See also¶
- Authentication: the credentials these checks run against.
- Organizations & members: managing roles in practice.
- CI uploads: choosing a token role.
- Audit events: every permission change is recorded.