Skip to content

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:

  1. Organization role. Are you a member of the organization, at a high enough level?
  2. Project role. Do you have the necessary access to this specific project?
  3. Token grants. If a token authenticated the request, do its scopes or its granted role cover the operation?
  4. 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 ALL that means an organization Manager or Admin, or an Admin on at least one project in the organization. A project Admin's ALL token 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 ALL is deliberately not among them, so an ALL-scoped personal access token has to be created over the API. GET /api/v1/pats/grantable-scopes reflects this: it returns the per-scope boolean map with the composite deliberately absent, and a developer who may grant everything simply sees every entry true.

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

  1. Default to the lowest role that works. It is easy to raise and awkward to un-leak.
  2. Use project memberships for contractors rather than organization roles.
  3. Use project access tokens for CI and personal access tokens for your own scripts.
  4. 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.
  5. Review periodically. The member list, tester list, and token lists all show who has what.

See also