How to fix auth/claims-too-large: Custom claims payload exceeds 1000-byte limit in Firebase

FirebaseINTERMEDIATEMEDIUMUpdated Dec 18, 2025ยท 122 views

This error occurs when attempting to set custom claims on a Firebase user that exceed the 1000-byte size limit. Firebase restricts custom claims to keep authentication tokens lightweight and performant.

Quick fix

Fixes auth/claims-too-large

import * as admin from 'firebase-admin';

async function checkClaimsSize(uid: string) {
  const user = await admin.auth().getUser(uid);
  const claims = user.customClaims || {};
  const claimsString = JSON.stringify(claims);
  const byteSize = Buffer.byteLength(claimsString, 'utf8');

  console.log('Claims:', claims);
  console.log('Size:', byteSize, 'bytes');
  console.log('Remaining:', 1000 - byteSize, 'bytes');

  return byteSize;
}
  1. Measure your current claims size
  2. Reduce claims to minimal identifiers
  3. Move large data to Firestore
  4. Optimize claim keys and values
firebase โ€” error
import * as admin from 'firebase-admin';
async function checkClaimsSize(uid: string) {
const user = await admin.auth().getUser(uid);
const claims = user.customClaims || {};
const claimsString = JSON.stringify(claims);
const byteSize = Buffer.byteLength(claimsString, 'utf8');
console.log('Claims:', claims);
console.log('Size:', byteSize, 'bytes');
console.log('Remaining:', 1000 - byteSize, 'bytes');
return byteSize;
}
auth/claims-too-large: Custom claims payload exceeds 1000-byte limit

What this error means

This error is thrown by Firebase Authentication when you try to set custom claims on a user account that exceed the 1000-byte limit. Custom claims are additional key-value pairs added to a user's ID token to implement role-based access control or store authorization metadata. Firebase enforces this limit because custom claims are embedded in the JWT (JSON Web Token) that gets sent with every authenticated request. Since tokens are transmitted with each API call to Firebase services (Firestore, Storage, Functions, etc.), larger tokens increase network overhead and can degrade application performance. The 1000-byte limit applies to the entire serialized JSON object of custom claims, not individual claim values. This includes the JSON structure itself (braces, quotes, commas), so the actual data you can store is slightly less than 1000 bytes.

Typical symptoms

  • Error thrown when calling admin.auth().setCustomUserClaims() with large claim objects
  • Authentication works but fails when trying to update user claims
  • Application logs show "auth/claims-too-large" error messages
  • Cloud Functions fail when attempting to set user roles or permissions
  • Claims successfully set for some users but fail for others with more data

Common causes

  1. Custom claims object contains too much data (arrays, nested objects, long strings)
  2. Storing entire user profile data or configurations in custom claims instead of just identifiers
  3. Including verbose permission lists or multiple large role definitions
  4. Adding redundant data that could be stored in Firestore or Realtime Database
  5. Accumulating claims over time without removing obsolete ones
  6. Using long descriptive keys or values that could be shortened or encoded

How to fix "auth/claims-too-large: Custom claims payload exceeds 1000-byte limit"

1Measure your current claims size

Calculate how many bytes your claims object is using:

typescript
import * as admin from 'firebase-admin';

async function checkClaimsSize(uid: string) {
  const user = await admin.auth().getUser(uid);
  const claims = user.customClaims || {};
  const claimsString = JSON.stringify(claims);
  const byteSize = Buffer.byteLength(claimsString, 'utf8');

  console.log('Claims:', claims);
  console.log('Size:', byteSize, 'bytes');
  console.log('Remaining:', 1000 - byteSize, 'bytes');

  return byteSize;
}

This helps you understand how close you are to the limit and identify which claims consume the most space.

2Reduce claims to minimal identifiers

Keep only essential authorization data in custom claims. Use simple role names or IDs instead of full objects:

Bad approach (too large):

typescript
await admin.auth().setCustomUserClaims(uid, {
  role: 'admin',
  permissions: ['read', 'write', 'delete', 'manage-users', 'manage-roles'],
  metadata: {
    department: 'Engineering',
    team: 'Backend',
    location: 'San Francisco',
    manager: 'john@example.com'
  },
  features: {
    betaAccess: true,
    premiumFeatures: ['feature1', 'feature2', 'feature3']
  }
});

Good approach (minimal):

typescript
await admin.auth().setCustomUserClaims(uid, {
  role: 'admin',
  dept: 'eng',
  premium: true
});

Store detailed information in Firestore and reference it when needed.

3Move large data to Firestore

Store comprehensive user data in Firestore and use custom claims only for access control:

typescript
// Set minimal claims for authorization
await admin.auth().setCustomUserClaims(uid, {
  role: 'admin',
  orgId: 'org_123'
});

// Store detailed user data in Firestore
await admin.firestore().collection('userProfiles').doc(uid).set({
  permissions: ['read', 'write', 'delete', 'manage-users'],
  metadata: {
    department: 'Engineering',
    team: 'Backend',
    location: 'San Francisco',
    manager: 'john@example.com'
  },
  features: {
    betaAccess: true,
    premiumFeatures: ['feature1', 'feature2', 'feature3']
  }
});

In your client code, fetch additional data when needed:

typescript
import { getAuth } from 'firebase/auth';
import { doc, getDoc } from 'firebase/firestore';

async function getUserData() {
  const user = getAuth().currentUser;
  const token = await user?.getIdTokenResult();

  // Access minimal claims from token
  const role = token?.claims.role;
  const orgId = token?.claims.orgId;

  // Fetch detailed data from Firestore
  const profileDoc = await getDoc(doc(db, 'userProfiles', user.uid));
  const profile = profileDoc.data();

  return { role, orgId, ...profile };
}
4Optimize claim keys and values

Use shorter key names and abbreviations to save space:

typescript
// Before (74 bytes)
{
  "isAdministrator": true,
  "organizationIdentifier": "org_12345",
  "subscriptionLevel": "premium"
}

// After (43 bytes) - saves 31 bytes
{
  "admin": true,
  "org": "org_12345",
  "sub": "premium"
}

For arrays, use numeric IDs or codes instead of descriptive strings:

typescript
// Before (85 bytes)
{
  "permissions": ["read-users", "write-users", "delete-users"]
}

// After (32 bytes) - saves 53 bytes
{
  "perms": [1, 2, 3]  // Map codes to permissions in your app
}
5Implement a claims validation function

Create a helper function that validates claims size before setting them:

typescript
import * as admin from 'firebase-admin';

const MAX_CLAIMS_SIZE = 1000;

async function setCustomClaimsSafely(
  uid: string,
  claims: Record<string, any>
): Promise<void> {
  const claimsString = JSON.stringify(claims);
  const byteSize = Buffer.byteLength(claimsString, 'utf8');

  if (byteSize > MAX_CLAIMS_SIZE) {
    throw new Error(
      'Claims size (' + byteSize + ' bytes) exceeds limit (' + MAX_CLAIMS_SIZE + ' bytes). ' +
      'Reduce claims by ' + (byteSize - MAX_CLAIMS_SIZE) + ' bytes.'
    );
  }

  await admin.auth().setCustomUserClaims(uid, claims);
  console.log('Claims set successfully (' + byteSize + '/' + MAX_CLAIMS_SIZE + ' bytes)');
}

// Usage
try {
  await setCustomClaimsSafely(uid, { role: 'admin', org: 'org_123' });
} catch (error) {
  console.error('Failed to set claims:', error.message);
  // Fall back to storing in Firestore
}

Advanced notes

Token Propagation Delay

Custom claims are embedded in the user's ID token when it's issued. After updating claims, the user must refresh their token to see the changes:

typescript
// Force token refresh on client
const auth = getAuth();
if (auth.currentUser) {
  await auth.currentUser.getIdToken(true); // Force refresh
  const token = await auth.currentUser.getIdTokenResult();
  console.log('Updated claims:', token.claims);
}

Tokens are automatically refreshed every hour, but you may need to force a refresh immediately after updating claims for real-time permission changes.

Hybrid Approach: Claims + Firestore

A common pattern is to use custom claims for coarse-grained access control (admin/user roles) and Firestore for fine-grained permissions:

typescript
// Custom claims (fast, available in Security Rules)
{ "role": "admin", "orgId": "org_123" }

// Firestore security rules
allow read, write: if request.auth.token.role == "admin"
                   && resource.data.orgId == request.auth.token.orgId;

// Detailed permissions in Firestore (flexible, no size limits)
/userProfiles/{uid}/permissions: {
  canManageUsers: true,
  canDeleteData: false,
  allowedFeatures: [...],
  restrictions: [...]
}

Character Encoding Considerations

The 1000-byte limit is based on UTF-8 encoding. Multi-byte characters (emojis, special characters) consume more bytes than ASCII characters. For example, an emoji can take 3-4 bytes.

Monitoring Claims Usage

Set up monitoring to track claims size across your user base:

typescript
async function auditClaimsUsage() {
  const { users } = await admin.auth().listUsers(1000);
  const stats = users
    .map(user => ({
      uid: user.uid,
      size: Buffer.byteLength(JSON.stringify(user.customClaims || {}), 'utf8')
    }))
    .filter(s => s.size > 800); // Flag users near limit

  console.log('Users approaching claims limit:', stats);
}

Frequently asked questions

What does "auth/claims-too-large" mean?
This error is thrown by Firebase Authentication when you try to set custom claims on a user account that exceed the 1000-byte limit. Custom claims are additional key-value pairs added to a user's ID token to implement role-based access control or store authorization metadata. Firebase enforces this limit because custom claims are embedded in the JWT (JSON Web Token) that gets sent with every authenticated request.
How do I fix "auth/claims-too-large"?
This error occurs when attempting to set custom claims on a Firebase user that exceed the 1000-byte size limit. Firebase restricts custom claims to keep authentication tokens lightweight and performant.
What causes "auth/claims-too-large"?
Custom claims object contains too much data (arrays, nested objects, long strings) Storing entire user profile data or configurations in custom claims instead of just identifiers Including verbose permission lists or multiple large role definitions
Is the "auth/claims-too-large" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading