Every environment can add custom claims to the session tokens Authdog issues, so your application reads roles, groups, or profile attributes straight from the token instead of making an extra lookup. Mappings are defined per environment and applied at sign-in, magic link verification, MFA elevation, and token refresh.

Custom claims are strictly additive: they never replace the standard claim set, and they never block a sign-in.

## Configure mappings

In the [Authdog console](https://console.authdog.com):

1. Select the project and environment.
2. Open **Authentication > JWT Claims**.
3. Edit the claims document in the JSON editor.
4. Save. The editor validates the document, reports errors inline, and refuses to save an invalid one.

The document maps a claim name to a source. Two forms are accepted:

```json
{
  "roles": "roles",
  "groups": "groups",
  "tenant": { "source": "static", "value": "acme" },
  "dept": { "source": "metadata", "key": "department" },
  "legacy_id": { "source": "externalId", "enabled": false }
}
```

The shorthand string form names the source; use the object form when you need `value`, `key`, or `enabled`. Setting `"enabled": false` keeps a mapping in the document without emitting the claim — handy for staging a claim, or for switching one off without losing its definition.

Claim names may contain letters, digits, and `_ . : / -`, up to 128 characters.

## Sources

| Source | Emits |
| --- | --- |
| `roles` | Array of role slugs |
| `groups` | Array of group slugs |
| `email` | Primary email address |
| `displayName` | Display name |
| `givenName` | Given (first) name |
| `familyName` | Family (last) name |
| `username` | Username |
| `externalId` | Stable external user id |
| `metadata` | Value at `key` in the user's metadata |
| `static` | The literal in `value` |

`roles` covers roles assigned directly, roles inherited through group membership, and roles held via an active time-bound elevated access grant. Slugs are deduplicated and sorted, so the claim stays byte-stable between tokens for an unchanged user.

`metadata` requires a `key`. `static` requires a `value`.

## Emission rules

- A source that yields nothing is omitted rather than written as `null`. Check for claim presence, not for a null value.
- `roles` and `groups` are always emitted when mapped, as `[]` when the user has none. A configured array claim is safe to read without a presence check.
- Mappings are applied in a stable order by claim name.

## Reserved claims

These claims are load-bearing for token verification and authorization, and a mapping that targets one is dropped rather than applied:

`iss`, `sub`, `aud`, `exp`, `iat`, `nbf`, `jti`, `scp`, `env`, `egat`, `sid`, `externalid`

Namespace your own claims — for example `https://acme.com/dept` or `acme_dept` — so a future standard claim cannot collide with one of yours.

## Discovery

Configured claim names are advertised in `claims_supported` on the environment's OpenID discovery document, so a relying party can see which claims to expect.

## Failure behavior

Claim resolution is best-effort. A broken mapping or a transient database error never blocks authentication: the token is issued with the standard claim set only, and the failure is logged. Never build a security control on the assumption that a custom claim is present — treat a missing claim as "no grant", and keep server-side checks the source of truth for sensitive operations.

## Size

Claims travel with the token on every request, so large arrays and long metadata values inflate headers and can trip proxy header limits. Map only the few attributes your application routes on; fetch the rest through the [API](/docs/api).

## Related

- [Sessions and tokens](/docs/concepts/sessions-tokens)
- [Roles and permissions](/docs/permissions)
- [Backend requests](/docs/backend)
- [Users](/docs/users)
