Reference

Tokens and claims

Access, ID and refresh tokens, their claims and lifetimes, scopes and the claims they add, signing keys and algorithms.

View .md llms.txt

#Access tokens

For your API. By default a JWT (RFC 9068):

json
// header
{ "alg": "RS256", "kid": "k_8f2a…", "typ": "at+jwt" }
// payload
{
  "iss": "https://acme.9in.io",
  "sub": "usr_8k2…",              // the user, or the client ID for client-credentials tokens
  "aud": "https://api.acme.com",  // the API (the client ID when no audience was requested)
  "client_id": "app_7f3k2m9q",
  "scope": "openid profile orders:read",
  "iat": 1794200000,
  "exp": 1794203600,
  "jti": "…",
  "sid": "…",                     // the session (absent for client credentials)
  "auth_time": 1794199000
}

Opaque access tokens (9in_at_… followed by random characters) carry nothing: check them with introspection. Choose the format per tenant (Tokens & Keys), per API, or per application for tokens without an API.

Access tokens don't include profile claims or amr; get those from the ID token or /oauth/userinfo.

#ID tokens

For your app: who signed in and how. A JWT with typ: JWT, always signed with the tenant's default key (asymmetric).

Claim
iss, sub, aud (your client ID), azp, iat, exp
auth_timeWhen the user signed in (unix seconds)
nonceFrom the authorization request
sidThe session id
amrHow the user signed in: pwd, otp, social, fed (enterprise), link (login link), and mfa after a second factor
at_hashHash of the access token issued with it (OIDC)
Profile claimsDepending on the scopes (below)
Custom fieldsFields marked "include as a claim", with the profile scope

#Refresh tokens

Opaque, issued with offline_access when the application has the refresh token grant (and the API allows refresh tokens). They rotate: every use returns a new refresh token. Using one that was already used revokes the whole family (token.reuse_detected in the activity log). They stop working when their session ends, the user is blocked or deleted, or they're revoked.

#Lifetimes

DefaultRangeSet per
Access token1 hour1 minute – 24 hoursTenant, API, application
ID token1 hour1 minute – 24 hoursTenant, application
Refresh token30 days5 minutes – 1 yearTenant, application
Authorization code60 seconds10 seconds – 10 minutesTenant
Session30 days (sliding)5 minutes – 1 yearTenant

For access tokens, an application's lifetime wins over its API's, which wins over the tenant's.

#Scopes and claims

ScopeGives
openidAn ID token; sub
profilename, given_name, middle_name, family_name, nickname, preferred_username, picture, website, gender, locale, zoneinfo, birthdate, and custom-field claims
emailemail, email_verified
phonephone_number, phone_number_verified
offline_accessA refresh token
Your API's scopesListed in the access token's scope

Claims with no value are left out.

#Signing keys

Each tenant has a key library (Tokens & Keys):

  • Algorithms: RS256, RS384, RS512, PS256, PS384, PS512 (RSA 2048 or 4096 bits), ES256, ES384, EdDSA (Ed25519), and HS256, HS384, HS512 (shared secrets).
  • Generate keys, or import your own: a PKCS#8 PEM, a private JWK, or an HMAC secret.
  • The default key (asymmetric) signs ID tokens and every access token whose API or application doesn't choose another key. New tenants start with an RS256 key.
  • Per API or application: any key from the library, so an API can use ES256 or a shared HMAC secret.
  • Rotation: add a key, make it the default, then retire the old one. Retired keys stop signing but stay in the JWKS until you delete them, so tokens signed earlier keep verifying.
  • HMAC keys are never published; the secret is shown once when it's created. A token signed with one is only accepted for the API or application that uses that key.

Verifiers must use the algorithm of the key named by kid, not a fixed list: an API's key can be ES256 or EdDSA.