Scopes and claims
The scopes Authio understands, the claims each one adds to the ID token, the access token and UserInfo, and how to create scopes and claims of your own.
A scope is a permission an application asks for in the authorization request; a claim is a field inside a token. Scopes decide which claims Authio writes: email adds the address, roles adds the roles, offline_access adds a refresh token.
A client can only ask for the scopes enabled on it, listed on the client’s Access tab. Asking for one that is not enabled is refused with invalid_scope before anyone signs in.
Standard scopes
| Scope | Assignment | What it adds |
|---|---|---|
openid | Default | Makes the request OpenID Connect: an ID token is issued and UserInfo answers. Granted only when the request names it. |
profile | Default | name, given_name, family_name, unique_name, preferred_username and updated_at |
email | Default | email and email_verified |
phone | Optional | phone_number and phone_number_verified |
roles | Default | The role claims of the access token — see Roles and permissions |
offline_access | Optional | A refresh token, on the grants that issue one |
address | Optional | Nothing: Authio keeps no postal address for users |
Default and optional scopes
Every scope has an assignment. A Default scope enabled on the client is granted whether or not the request names it; an Optional one only when the request asks for it. openid is the exception: it is granted only when requested.
What was granted is in the token’s scope claim, separated by spaces. Read it first when a claim you expected is missing.
Scopes about a person — openid, profile, email, phone, address and offline_access — never reach a token issued to a machine with the client credentials grant.
openid is required by default
Clients start with Require OpenID Connect on, in the client’s Configuration: an authorization request without openid is refused with invalid_scope. Turn it off for an application that only needs an access token to call an API and has no use for an ID token.
ID token, access token and UserInfo
The three answer different questions, and Authio fills them differently:
| Aspect | ID token | Access token | UserInfo |
|---|---|---|---|
| Meant for | Your application, to learn who signed in | Your API, as the credential of each call | Your application, to read the person’s current data |
aud | The client’s client_id | The API named with resource, or the audience configured on the client | — |
| Profile, email and phone | Name, username, email and phone, with their verification flags, whenever openid was granted | The claims of profile, email and phone, for each one granted | The claims of profile, email and phone, for each one granted, read at the time of the call |
| Roles | Never | With the roles scope | Never |
| Organization | org_id and org_alias | org_id and org_alias | — |
| Claim mappers | When the mapper targets it | When the mapper targets it | — |
| Lifetime | The client’s session lifetime | The client’s access token lifetime | — |
Access token claims
| Claim | Value |
|---|---|
iss | The realm’s issuer, such as https://authio.api.hyperio.tech/realms/acme |
sub | The user’s ID in the realm |
aud | The API named with resource, or the audience configured on the client |
azp | The client_id of the client the token was issued to |
scope | The granted scopes, separated by spaces |
typ | Bearer. ID tokens carry ID and refresh tokens Refresh. |
iat, nbf, exp, jti | Issue time, validity window and unique ID |
sid | The session the token belongs to |
auth_time | When the person authenticated |
amr | How they authenticated: pwd, otp, swk (passkey), user, mca, fed, plus mfa when two distinct factors were used |
acr | 1 for one factor, 2 for several, 3 for several with a phishing-resistant credential |
idp | The alias of the external provider, when the sign-in began at one |
org_id, org_alias | The organization of the sign-in — see Organizations |
{
"iss": "https://authio.api.hyperio.tech/realms/acme",
"sub": "6f1c2e7a-4b8d-4f0e-9a51-3c2d7e8b9f10",
"aud": "https://api.acme.com",
"azp": "acme-web",
"typ": "Bearer",
"scope": "openid profile email offline_access",
"sid": "0b7e4c2a-9d1f-4a6e-8c3b-5f2d1e9a7c40",
"auth_time": 1791370800,
"acr": "2",
"amr": ["pwd", "otp", "mfa"],
"email": "maria@acme.com",
"email_verified": true,
"name": "Maria Silva",
"given_name": "Maria",
"family_name": "Silva",
"unique_name": "maria",
"preferred_username": "maria",
"updated_at": 1790000000,
"iat": 1791370800,
"nbf": 1791370800,
"exp": 1791372600,
"jti": "e5a8c1d4-7b2f-4c9e-a3d6-1f8b0e4c7a25"
}UserInfo
UserInfo returns the person’s current data, read at the time of the call: a name changed or an email confirmed since sign-in shows up at once. Call it with the access token, by GET or POST.
curl https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/userinfo \
-H "Authorization: Bearer $ACCESS_TOKEN"subis always present;profile,emailandphoneeach add their claims when the token was granted them.- Empty values are left out.
- A token without
openidgets403withinsufficient_scope; an invalid token, or one whose user is no longer active, gets401withinvalid_token.
Custom scopes
Create scopes for your own APIs, such as invoices:read or reports.export, in Permissions › Global Scopes with New Scope — or exclusive to a realm or a client, from that record’s page. A scope exclusive to a client is enabled on it as soon as it is created. Scopes that belong to one API can also be declared on its resource server.
| Field | Rules |
|---|---|
| Name | Up to 200 characters of printable ASCII, without spaces, quotes or backslashes. The standard scopes above, role_list, web-origins, acr and microprofile-jwt are reserved. |
| Consent description | Up to 500 characters, shown to the person on the consent screen when the client asks for consent. |
| Protocol | A classification: OpenID Connect, OAuth 2.0, Client Credentials or SAML. Scopes classified as SAML never enter a JWT. |
| Assignment | Default or Optional, as described above. |
A custom scope adds its name to the scope claim and nothing else; your API checks it there. To put data into the token, use a claim mapper.
Custom claims
Claim mappers add claims of your own to the tokens a client issues. Open the client’s Access tab, go to Claim mappers and add one rule per claim: its name, where its value comes from and which tokens receive it.
| Source | Value |
|---|---|
| User property | Email, email confirmed, username, first name, last name, full name, phone, phone confirmed, account creation date or status |
| Roles | The names of the person’s roles, direct or through a group |
| Groups | The names of the person’s active groups |
| Fixed value | A constant you type, up to 512 characters |
- Each rule writes to the access token, the ID token or both; at least one.
- The claim name has up to 64 characters, starts with a letter or
_, uses only letters, digits,_,:and-, and is unique among the client’s mappers. - Names the protocol writes are refused:
iss,aud,exp,nbf,iat,jti,azp,nonce,typ,alg,kid,sub,scope,client_id,sid,acr,amr,idp,at_hash,c_hashandauth_time. - Mappers do not depend on scopes: an active mapper writes its claim on every token it targets. A source with several values, such as roles, is written as an array.
Before saving, the mapper screen previews the resulting token for a real user of the client. Claims added to a user directly, on the Permissions step of the user’s edit screen, go into that user’s access tokens.