Skip to content

Claims

Claims are JSON properties inside the id_token JWT and the userinfo response. The set you receive depends on the scopes you requested.

Standard claims (openid)

Claim Type Description
iss string Always https://id.littlexlittle.org.
sub string Stable per-user identifier (the accounts.code value).
aud string Your client_id.
exp int Expiry (Unix timestamp).
iat int Issued-at.
auth_time int When the user last authenticated upstream.
nonce string Echoed from the authorize request. Verify it matches what you sent.

profile scope

Claim Type Description
name string Display name.
given_name string First name.
family_name string Last name.
picture string URL to avatar (CDN-served).
locale string BCP 47 locale, e.g. en-US.
updated_at int Last profile change (Unix).

email scope

Claim Type Description
email string Primary verified email if available, else primary unverified.
email_verified bool Whether the email was verified by Little X Little.

phone scope

Claim Type Description
phone_number string E.164 format.
phone_number_verified bool Verified via SMS OTP.

address scope

Claim Type Description
address.street_address string
address.locality string City.
address.region string State / province.
address.postal_code string
address.country string ISO 3166-1 alpha-2.
address.formatted string Newline-joined full address.

Little X Little custom claims

All custom claims are namespaced lxl.* to remain spec-compliant.

Claim Type Scope Description
lxl.app string lxl.access NGO app code, e.g. bootim.
lxl.access string[] lxl.access Permission strings, e.g. ["Website:Media","Donations:View"].
lxl.master bool lxl.master True for master administrators.
lxl.role string lxl.role "Branch › Position" joined.
lxl.links string[] lxl.links Linked external providers, e.g. ["google","linkedin"].

Reading claims

php $payload = $client->verifyIdToken($id_token); if (in_array('Website:Media', $payload['lxl.access'] ?? [], true)) { // user can manage Website / Media on this NGO }

js function decode(jwt) { const [, payload] = jwt.split('.'); return JSON.parse(atob(payload.replace(/-/g,'+').replace(/_/g,'/'))); } const claims = decode(idToken); if (claims['lxl.master']) { /* admin features */ }

Decode ≠ verify

Decoding a JWT without verifying its signature is insecure. Never trust claims you haven't verified against JWKS — use a library that does both.