Lesson 6 / 25
Auth State, ID Tokens and Custom Claims
Knowing who is signed in, everywhere.
Listeners, tokens and claims
Sign-in state is restored asynchronously when the page loads, so do not read auth.currentUser once at startup; subscribe with onAuthStateChanged and render based on the user it delivers. Each signed-in user has a short-lived ID token (a JWT, refreshed automatically by the SDK) that Firebase services verify; you can send it to your own backend and verify it with the Admin SDK (verifyIdToken). Custom claims are small key-value pairs (such as { admin: true }) set only from trusted code with the Admin SDK; they appear in the token and in rules as request.auth.token. Claims are size-limited (check the docs) and reach the client only after the token refreshes.
Listening for the user and reading claims
Client and Admin SDK, TypeScript.
// client
import { getAuth, onAuthStateChanged } from "firebase/auth";
const auth = getAuth(app);
onAuthStateChanged(auth, async (user) => {
if (!user) return showSignIn();
const result = await user.getIdTokenResult(); // pass true to force a refresh
showApp({ uid: user.uid, isAdmin: result.claims.admin === true });
});
// trusted server code (Cloud Function or your backend)
import { getAuth as getAdminAuth } from "firebase-admin/auth";
export async function makeAdmin(uid: string) {
await getAdminAuth().setCustomUserClaims(uid, { admin: true });
// the user sees the claim after their ID token refreshes
}Claims are for roles, not profiles
Keep claims tiny (roles, tenant id). Store profile data such as names and preferences in Firestore.
Quick check: Where can custom claims be set?
- In the web config object
- From any client with updateProfile
- Inside Security Rules
- Only from trusted code using the Admin SDK
Answer
Only from trusted code using the Admin SDK — Clients must not grant themselves roles.