Scopes
A scope is a named permission. The customer's administrator sees the scopes an application asks for, in plain words, when deciding whether to approve it, and the API checks them on every request. There are nine.
The nine scopes
| Scope | Lets the application | Needs the Admin role |
|---|---|---|
contacts:read | Read every contact in the account and the information kept about them. | No |
contacts:write | Create contacts and change existing ones. | Yes |
consent:read | Read who is subscribed to which lists and who has opted out. | No |
consent:write | Record opt-ins and opt-outs. | Yes |
subscription-lists:read | Read the subscription lists. | No |
subscription-lists:write | Create subscription lists and change them. | Yes |
email-templates:read | Read the saved email templates. | No |
email-templates:write | Create email templates and change them. | Yes |
integrations:read | Read which integrations, such as a CRM, are connected and what they sync. | No |
Each route in the route reference says which scope it needs. The nine scopes are the vocabulary, and a release can contain a scope before it contains every route that uses it, so the route reference, not this table, is the list of what you can call.
Rules that hold for all of them:
writedoes not implyread. An application that must read what it writes asks for both.- There is no wildcard scope. Each is asked for by name.
- Scope strings are permanent. They are never renamed or removed, because that would break every integrator holding one. New scopes may be added.
consent:*is separate fromcontacts:*on purpose, so that the access customers most readily give an outsider, recording who has opted in or out, can be granted without handing over the contact database.
Not API scopes
Two scopes you will also send belong to the sign-in, not to this API:
user:org:readputs the organization selector on the consent screen, so a person in several organizations chooses the one they are granting. It appears in the protected-resource metadata'sscopes_supportedfor that reason, though it is not one of the nine. Always request it.offline_accessis what makes the authorization server issue a refresh token.
Neither is ever listed in the scopes of a GET /meta response.
Authentication covers both.
The scopes you actually get
Asking for a scope is not the same as holding it. The scopes the API honours for a
credential are the ones that survive three filters, and GET /meta reports the
result in scopes:
- The scopes on the token. What you asked for at sign-in and the person consented to.
- What the customer approved. An administrator approves an application together
with the scopes it held when it first connected, and that set is a ceiling.
If the application later signs in again asking for more, the extra scopes are
dropped, not refused: the application keeps working, and
/metaquietly shows the smaller set. This is why you ask for everything you will ever need on the first connection. - What the person who signed in may delegate. A write scope is honoured only while that person holds the Admin role in the organization. See below.
Compare scopes with what your application needs when it starts, and before a long
job, rather than when the first write fails with 403 insufficient_scope. That
error's WWW-Authenticate header lists every scope the route needs in one go.
Write scopes need the Admin role
The four :write scopes are honoured only for a person whose role in the customer's
organization is org:app_admin, which the app calls Admin. That is a custom
role, and it is not the same thing as Clerk's built-in org:admin. Being an
administrator of the organization in the identity provider does not delegate write
scopes; being an Admin of the app does. A person who administers the organization
but is not an app Admin gets none, and an app Admin who is not an organization
administrator gets all of them.
So if your writes are missing, look here first. The symptoms are that GET /meta
shows only the :read scopes, and the write routes answer 403 insufficient_scope,
even though you asked for the write scopes.
- Check who signed in. A teammate who is not an Admin can authorize an application, but cannot hand it write access.
- The role is checked against the person's current membership, not the one they
had when they signed in, and the answer is remembered briefly. A promotion takes a
short while to show up in
/meta, and so does a demotion. If an integration's write access disappears without anyone touching the application, someone's role changed. - For anything that runs in production, authorize as a dedicated service user rather than a person; Using the API without a browser explains why.
Asking for more later
Because the approval is a ceiling, signing in again with a longer scope does not
widen it, and the extra scopes are not served. Today the only way to widen an
application's access is to have the administrator revoke the application in Settings
and approve it again:
- Stop the application, so that nothing keeps calling with the old token.
- The administrator revokes the application.
- Sign in again asking for the full set of scopes, and make the application's next request with the new token. The scopes of the request that reconnects are the ones recorded.
- The application is held for approval, as after any revocation; the administrator approves it, and the approval now covers the new set.
See Connected applications for the administrator's side.
Related guides
- Authentication
- Route reference
- Connected applications: how an administrator sees and approves the scopes