Why custom claims?
By default, an access token issued by Prelude only contains the standard JWT claims (iss, sub, exp, …) and the scopes granted to the session. If your backend needs more context — the user’s locale, IP address, your own internal user ID, a loyalty tier — you can declare it once in a claims mapping configuration and Prelude will inject it into every access token issued for that application.
You can mix three kinds of values in the same configuration:
- Hardcoded values — constants that always appear in the token (e.g. an API version number).
- Built-in inputs — data Prelude already knows about the user or the session (user ID, IP, locales, emails, …).
- Profile custom claims — arbitrary data you store on the user’s profile via the Management API.
How it works
You configure the mapping once per application through the Management API. From that moment on, every access token Prelude issues for that application — at login, refresh, or step-up — embeds the resolved claims.When you update the claims mapping, existing sessions automatically pick up the new configuration on their next refresh. There is nothing to do on the client side.
Mapping format
A claims mapping is a free-form JSON object passed under themapping key. Each top-level key becomes a claim in the access token. Nested objects are preserved as-is.
Hardcoded values
Any non-object value (string, number, boolean) is copied verbatim into the token:Built-in inputs
Use the$input / $type operators to reference data that Prelude already knows about the user and the session. Both operators are required together.
Profile custom claims
Any field stored on the user’s profile viaPATCH /v2/session/apps/{appID}/users/{userID}/profile can be referenced with the $custom_claim operator:
null).
Profile claims are resolved at every token issuance, so updates to a user’s profile are reflected in the next access token without requiring re-authentication.
Nested claims
Mapping objects can be nested arbitrarily. Anything that is not a$input/$type or $custom_claim template is treated as a plain nested object:
Available inputs
The following template names can be used with$input. Each input has a fixed set of supported $type values.
| Input | Supported types | Description |
|---|---|---|
user_id | uuid, string | The Prelude user ID. |
session_id | uuid, string | The current session ID. |
external_id | string | The user’s external ID, set via the Management API. |
is_first_session | bool, int, string | Whether this is the user’s first session. |
ip | string | The IP address of the client when the session was created. |
country_code | string | ISO 3166-1 alpha-2 country code derived from the IP address. |
preferred_language | string | The user’s preferred language, taken from the profile. |
locales | string-array, string | The list of locales known for the user (from social login or profile). |
given_name | string | The user’s given name (from social login or profile). |
family_name | string | The user’s family name (from social login or profile). |
picture | string | URL of the user’s profile picture (from social login or profile). |
emails | string-array, string | All verified email identifiers attached to the user. |
phone_numbers | string-array, string | All verified phone identifiers attached to the user (E.164). |
Type conversions
| Type | Behavior |
|---|---|
string | Renders the value as a string. Booleans become "true"/"false", numbers are stringified, arrays are joined with a single space. |
uuid | Returns the canonical UUID string representation of an ID. Only valid for user_id and session_id. |
bool | Coerces the value to a boolean. Strings "true"/"false" and non-zero numbers are accepted. |
int | Coerces the value to an integer. |
string-array | Returns the value as a JSON array of strings. A scalar input is wrapped in a single-element array. |
Reserved claims
The following claims are reserved by the JWT specification and cannot be used as top-level keys in your mapping. They are managed by Prelude and would be stripped or rejected:iss · sub · aud · exp · nbf · iat · jti · sid · scope
Attempting to set any of them at the root level returns 400 invalid_claim_override. They can still appear as keys inside nested objects (e.g. "metadata": { "iss": "..." }).
Managing the configuration
Each application can have at most one claims mapping configuration. The Management API exposes the standard CRUD operations.Create the configuration
201 Created with the saved configuration. If a configuration already exists, the request fails with 409 claims_mapping_config_already_exists — use PUT instead.Update the configuration
Errors
| HTTP status | Code | When it happens |
|---|---|---|
| 400 | invalid_request | The request body is malformed, or a template object mixes incompatible operators (e.g. $input without $type, or $custom_claim together with $input). |
| 400 | invalid_template_type | The $input value is not a known template name, or the $type is not supported for that input (e.g. int for emails). |
| 400 | invalid_claim_override | A reserved JWT claim (iss, sub, aud, exp, nbf, iat, jti, sid, scope) appears at the root of the mapping. |
| 409 | claims_mapping_config_already_exists | POST was called while a configuration already exists. Use PUT to update it. |
Validation rules
When you submit a mapping, Prelude validates the structure before storing it:- A template object using
$inputmust also include$type, and only those two keys. - A template object using
$custom_claimmust contain only that key. $input,$type, and$custom_claimvalues must be strings.- The
$inputvalue must match one of the names in Available inputs. - The
$typevalue must be one of the types listed for that input. - Reserved JWT claims cannot appear at the root level.
Verifying tokens
Custom claims are signed alongside the standard JWT claims, so verifying a token has not changed: fetch the public keys from your application’s JWKS endpoint and verify the signature as usual. Once the signature is valid, the custom claims you configured can be read straight from the JWT payload.What’s next?
JWKS
Verify the signature of access tokens issued by the Session API.
Claims Configuration API
Full API reference for managing the claims mapping configuration.