---
title: Claims
---

# Claims

Claims are JSON properties inside the `id_token` JWT and the userinfo response. The set you receive depends on the [scopes](scopes.md) 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"

    ```php
    $payload = $client->verifyIdToken($id_token);
    if (in_array('Website:Media', $payload['lxl.access'] ?? [], true)) {
        // user can manage Website / Media on this NGO
    }
    ```

=== "JavaScript"

    ```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 */ }
    ```

!!! warning "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.
