TryMellon
Navigation

Custom claims (SDK)

Inject application-defined claims into the session JWT.

Custom claims

Custom claims let you propagate application metadata (e.g. role, company_id, wallet_address) inside the session JWT instead of joining a separate user table on every authenticated request.

Claims are gated by a per-application whitelist schema configured in the dashboard (see “Define schema” below). Anything not in the whitelist is rejected with CUSTOM_CLAIM_NOT_ALLOWED.

Limits

  • Up to 10 keys per token.
  • Total payload ≤ 2 KB of JSON.
  • Scalar values only: string, number, boolean. No nested objects/arrays.

Exceeding any limit returns CUSTOM_CLAIMS_TOO_LARGE or CUSTOM_CLAIM_NOT_ALLOWED.

Define the schema (dashboard)

Dashboard → Applications → [your app] → Advanced → Custom claims schema.

Today the schema is read-only in the UI; updates go through PATCH /v1/applications/:id with custom_claims_schema in the body. Editor UI is on the F0 follow-up roadmap.

Example schema:

{
  "role":           { "type": "string" },
  "company_id":     { "type": "number" },
  "wallet_address": { "type": "string" }
}

Pass claims at login

import { TryMellon } from '@trymellon/js';

const client = TryMellon.create({ clientId: '…' }).value!;

const result = await client.signIn({
  externalUserId: 'user_123',
  customClaims: {
    role: 'admin',
    company_id: 42,
  },
});

customClaims is also accepted on signUp and enroll.

Read claims on the backend

Claims live under the https://trymellon.dev/claims namespace in the JWT (per the OIDC custom-claim convention to avoid collisions).

import { jwtVerify, createRemoteJWKSet } from 'jose';

const JWKS = createRemoteJWKSet(
  new URL('https://api.trymellonauth.com/.well-known/jwks.json'),
);

const { payload } = await jwtVerify(token, JWKS, {
  issuer: 'https://api.trymellonauth.com',
});

const claims = payload['https://trymellon.dev/claims'] as
  | { role?: string; company_id?: number; wallet_address?: string }
  | undefined;

console.log(claims?.role); // 'admin'

For Go and Python examples see Reading custom claims.

Use cases

ClaimWhy in JWT instead of a DB lookup
roleAuthorization decisions in middleware — no DB hit per request.
company_idMulti-tenant routing without an extra SELECT.
wallet_addressWeb3 dApps verifying intent on-chain — already proven during login.

Troubleshooting

ErrorCauseFix
CUSTOM_CLAIM_NOT_ALLOWEDKey not in the application’s whitelist.Add it to custom_claims_schema in the dashboard.
CUSTOM_CLAIMS_TOO_LARGE> 10 keys or > 2 KB.Drop to references (e.g. company_id instead of company_name + company_country + …).
Claim missing in JWTSchema rejects the value’s type.Make sure runtime type matches the schema declaration.