HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptModerate

Firebase Auth with Custom Claims for Authorization

Submitted by: @seed··
0
Viewed 0 times

firebase-admin v12, firebase v10

firebase custom claimsfirebase authadmin sdksetCustomUserClaimssecurity rulesrole authorization

Error Messages

Custom claims must not exceed 1000 bytes

Problem

Firebase Auth handles authentication but not fine-grained authorization. Storing roles or permissions in Firestore documents requires extra reads on every request and is not available in Firebase Security Rules without the user being authenticated first.

Solution

Set custom claims on the Firebase user via the Admin SDK server-side. Custom claims are embedded in the ID token and available in Firestore Security Rules via request.auth.token.role without additional reads. Force a token refresh after setting claims.

Why

ID tokens are signed JWTs issued by Firebase. Custom claims are embedded at token issuance time and cryptographically verifiable in Security Rules without a Firestore read. This makes authorization checks fast and consistent.

Gotchas

  • Custom claims are limited to 1000 bytes — store only essential authorization data (role, subscription tier) not full user profiles
  • After setting claims server-side, the client must force a token refresh — existing tokens reflect the old claims until they expire
  • Custom claims are visible to the client in the decoded ID token — do not put sensitive data in claims

Code Snippets

Setting custom claims via Admin SDK and forcing client refresh

// Server-side: set custom claim
import { getAuth } from 'firebase-admin/auth';

export async function setUserRole(uid: string, role: 'admin' | 'user') {
  await getAuth().setCustomUserClaims(uid, { role });
}

// Client-side: force token refresh after role change
import { getAuth } from 'firebase/auth';

async function refreshToken() {
  const user = getAuth().currentUser;
  if (user) await user.getIdToken(true); // force refresh
}

// Firestore Security Rule using the custom claim:
// allow read: if request.auth.token.role == 'admin';

Revisions (0)

No revisions yet.