Blog
Wild & Free Tools

JWT Custom Claims: How to Add, Read, and Namespace Them Correctly

Last updated: February 2026 5 min read
Quick Answer

Table of Contents

  1. What Are Custom Claims?
  2. Namespacing Custom Claims
  3. Adding Custom Claims When Issuing JWTs
  4. Reading Custom Claims
  5. Frequently Asked Questions

Beyond the standard registered claims (sub, iss, exp), a JWT payload can carry any custom data your application needs. Roles, permissions, tenant IDs, feature flags — these are private claims. Here is how to add them correctly and read them in code.

Custom Claims vs Registered Claims

JWT claims fall into three tiers:

Common custom claims in production apps: role, roles, permissions, org_id, tenant_id, plan, feature_flags. These let downstream services make authorization decisions without a database lookup.

How to Namespace Custom Claims (Required for Public Tokens)

If your JWT might ever be shared outside your system, use a URL namespace to avoid collisions with other claim names:

// Namespaced claims — safe for public or multi-party tokens
{
  "sub": "user_12345",
  "exp": 1735689600,
  "https://myapp.com/role": "admin",
  "https://myapp.com/org_id": "org_abc123",
  "https://myapp.com/permissions": ["read:reports", "write:invoices"]
}

Auth0 specifically requires this pattern — if you add custom claims without a URL namespace, Auth0 will silently strip them from the token.

For internal systems where the JWT never leaves your infrastructure, short names are fine:

{
  "sub": "user_12345",
  "role": "admin",
  "org_id": "org_abc123"
}
Sell Custom Apparel — We Handle Printing & Free Shipping

How to Add Custom Claims When Generating a JWT

// Node.js — jsonwebtoken
const jwt = require('jsonwebtoken');

const payload = {
  sub: userId,
  role: 'admin',
  org_id: orgId,
  permissions: ['read:reports', 'write:invoices']
};

const token = jwt.sign(payload, process.env.JWT_SECRET, {
  expiresIn: '15m',
  issuer: 'https://auth.myapp.com',
  audience: 'https://api.myapp.com'
});
# Python — PyJWT
import jwt
import datetime

payload = {
    'sub': user_id,
    'role': 'admin',
    'org_id': org_id,
    'permissions': ['read:reports', 'write:invoices'],
    'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=15),
    'iss': 'https://auth.myapp.com'
}

token = jwt.encode(payload, secret_key, algorithm='HS256')

How to Read Custom Claims After Decoding

Once you have decoded the JWT payload, custom claims are just regular JSON fields:

// JavaScript — after decoding or verifying
const payload = decodeJwt(token);  // or jwt.verify() on server
const role = payload.role;
const orgId = payload.org_id;
const permissions = payload.permissions || [];

// Check permission
if (!permissions.includes('write:invoices')) {
  return res.status(403).json({ error: 'Forbidden' });
}

For namespaced claims:

const role = payload['https://myapp.com/role'];
const permissions = payload['https://myapp.com/permissions'] || [];

Size warning: JWT payloads are sent with every request. Keep custom claims minimal — avoid including large arrays, nested objects, or data that changes frequently. A token over 4KB can cause issues with cookies and some HTTP headers.

Inspect Your JWT Custom Claims

Paste your token above to see all claims — including custom and namespaced ones — decoded and labeled instantly.

Open Free JWT Decoder

Frequently Asked Questions

Can I put an array of roles in a JWT claim?

Yes. A claim value can be any valid JSON type — string, number, boolean, array, or object. Arrays of roles or permissions are common: "roles": ["admin", "editor"]. Just watch the total token size.

Can I update custom claims after a token is issued?

No — a JWT cannot be modified after issuance without invalidating the signature. If a user's role changes, you need to issue a new token (the next login or token refresh will pick up the new role).

Should I put sensitive data in custom claims?

No. JWT payloads are base64-encoded, not encrypted. Anyone who has the token can decode and read all claims. Never put passwords, SSNs, credit card numbers, or private business data in a JWT payload.

Jake Morrison
Jake Morrison Security & Systems Engineer

Jake's conviction that files should never touch a third-party server is the foundation of WildandFree's zero-upload design.

More articles by Jake →
Launch Your Own Clothing Brand — No Inventory, No Risk