Sign-in and Access · 8 min read

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 profile or orders:read. Granted scopes are listed in the access token's scope claim.
  • A claim is one piece of data in a token, such as email or given_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:

TokenIssued forScopes decide
User token (authorization code)A user, through an appWhat the app may do for the user, and which user claims it sees
Client credentials tokenThe client itself, no userWhat a backend may do in the service APIs. No user claims.

Standard OpenID Connect scopes

ScopeClaims
openidNone of its own. Required to get an ID token at all.
profilename, given_name, family_name, nickname, preferred_username, gender, birthdate, locale
emailemail, email_verified
phonephone_number, phone_number_verified
addressaddress (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. 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. 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. 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. 4

    Save, then assign it

    A scope does nothing until a client has it under Default or Additional scopes.

RuleWhy 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. 1

    Open the web client

    Access admin → Web clients → your client, scopes section.

  2. 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 without scope fail.

  3. 3

    Set Additional scopes

    What the client may ask for on top. Default scopes can always be requested too.

  4. 4

    Save and test

    Request a token and decode it. Check scope in 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

TokenContainsRead by
ID tokeniss, 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.
  • scope in the access token is a space-separated string of the granted scopes.
  • aud comes from the client's audiences. A service refuses a token without its audience.
  • acr tells 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.

Related