Scopes and claims
Decide what apps may ask for and what user data ends up in their tokens. Create scopes, map Identity Store attributes to claims, and assign scopes to clients.
Scopes, claims and who gets them
- A scope is a named permission a client asks for, such as
profileororders:read. Granted scopes are listed in the access token'sscopeclaim. - A claim is one piece of data in a token, such as
emailorgiven_name. Access adds user claims when a granted scope has them mapped. - Default scopes are granted when the client asks for none. Additional scopes are granted only when the client asks for them.
- A client can only get scopes assigned to it. A request for a scope that isn't assigned, or doesn't exist, is refused.
Scopes work the same for both kinds of tokens, but mean different things:
| Token | Issued for | Scopes decide |
|---|---|---|
| User token (authorization code) | A user, through an app | What the app may do for the user, and which user claims it sees |
| Client credentials token | The client itself, no user | What a backend may do in the service APIs. No user claims. |
Standard OpenID Connect scopes
| Scope | Claims |
|---|---|
openid | None of its own. Required to get an ID token at all. |
profile | name, given_name, family_name, nickname, preferred_username, gender, birthdate, locale |
email | email, email_verified |
phone | phone_number, phone_number_verified |
address | address (an object with street_address, locality, region, postal_code, country) |
A claim appears only when the user has a value for it. Ask only for the scopes the app uses: every claim is personal data that the app then has to protect.
Create a scope with claims
- 1
Open Access admin → Scopes and add a scope
The name can be up to 255 characters: letters, digits,
:,.,_and-. Use a pattern such as<api>:<action>so names stay readable in tokens. - 2
Map claims (optional)
Pick the Identity Store attributes the scope releases. Each mapping is a response attribute: its name is the claim name, and it has a source and a location in that source.
- 3
Choose the consent type
Persistent consent (the default): the user agrees once, on the first request. Clear it to ask on every request.
- 4
Save, then assign it
A scope does nothing until a client has it under Default or Additional scopes.
| Rule | Why it matters |
|---|---|
| Claim names are case-sensitive and must be unique in a response. | Email and email are different claims. Pick one convention. |
| The default source is the Identity Store's stored attributes. Other attributes can come from the session, filled by the identity provider's result. | Use the session source for values only the sign-in knows, such as data from an external IdP. |
| Two attributes may share a name only if their sources differ. Then the Identity Store value wins. | A stored value overrides a session value of the same name. |
| Only attributes with a value become claims, unless the mapping has a default. | Apps must handle missing claims. |
Claims mapping needs the Identity Store integration on the identity provider the web client uses. Turn it on once, in that identity provider's integration settings. Without it, users sign in but the mapped claims are missing.
To manage scopes in code, use the Access configuration API. A scope update there replaces the whole scope, so send every field.
Assign scopes to clients
- 1
Open the web client
Access admin → Web clients → your client, scopes section.
- 2
Set Default scopes
What the client gets when it asks for nothing. For a sign-in app, at least
openid. An empty list makes requests withoutscopefail. - 3
Set Additional scopes
What the client may ask for on top. Default scopes can always be requested too.
- 4
Save and test
Request a token and decode it. Check
scopein the access token and the claims in the ID token.
For machine-to-machine clients, the scope builder shows the scopes each service operation needs. Keep the Default scopes, joined with spaces, within 1024 characters: past that the token endpoint answers HTTP 500. Move the rest to Additional scopes and request them with scope=. See machine-to-machine clients.
What ends up in each token
| Token | Contains | Read by |
|---|---|---|
| ID token | iss, sub, aud (your client ID), exp, iat, acr, at_hash, plus the user claims of the granted scopes. | Your app, once, at sign-in. |
| Access token (JWT) | iss, sub (the user, or the client for client credentials), aud, client_id, scope, exp, iat, nbf, jti, ver. Mapped user claims are not added by default. | The APIs the token is for. Apps should treat it as opaque. |
| Access token (opaque) | Nothing readable. A random string. | APIs, through token introspection. |
scopein the access token is a space-separated string of the granted scopes.audcomes from the client's audiences. A service refuses a token without its audience.acrtells the app how strongly the user authenticated. Check it before sensitive actions.
Need custom claims in the access token, or claims computed at sign-in? Access can call a token web hook while it mints the token, and an Identity Orchestration flow can answer that hook. Keep the hook fast and side-effect free: it runs on every token issued, and if it fails, token issuance fails. See Identity Orchestration flows and nodes.
Good practice
- Grant the least. Put only what every request needs under Default scopes.
- Don't put secrets, internal IDs or large data in claims. Tokens are signed but, unless you turn on ID token encryption, not encrypted, and they pass through the browser.
- Split read and write scopes so read-only clients can't change data.
- Leave consent on for third-party apps. Skip it only for your own apps.
- After any scope change, decode a fresh token to confirm. Don't trust a by-ID read straight after a change: it can lag for about two minutes.