All posts
authfirebase

Firebase Auth: A Practical Guide for Full-Stack Developers

A practical guide to Firebase Authentication — providers, ID token verification, custom claims, and where it fits next to Supabase and Clerk.

SR

Suhail Roushan

August 6, 2026

·
5 min read
·
0 views

Firebase Auth has been around longer than most alternatives on this list, and its biggest strength is still the same one it launched with: an enormous list of pre-built sign-in providers that just work, including ones other services don't bother supporting.

Firebase Authentication is Google's hosted auth service, part of the broader Firebase platform, supporting email/password, phone/SMS OTP, and a wide range of OAuth providers, plus anonymous auth for guest sessions. It issues JWTs (ID tokens) your backend verifies using the Firebase Admin SDK, and it integrates natively with the rest of Firebase (Firestore security rules, Cloud Functions) the same way Supabase Auth integrates with Postgres RLS.

Why Firebase Auth Matters (and When to Skip It)

Firebase Auth's provider breadth is genuinely wider than most alternatives — phone/SMS auth in particular is well-supported and battle-tested at scale, which matters for apps targeting regions where phone-based login is the norm over email. It's also free at reasonable scale, with pricing kicking in only for phone auth SMS costs and very high usage tiers.

Skip it if you're not already using Firestore or other Firebase products — like Supabase Auth's RLS advantage, Firebase Auth's main structural benefit (Firestore security rules referencing the authenticated user) disappears if your database is elsewhere.

Getting Started with Firebase Auth

Client-side sign-in with a provider:

import { initializeApp } from "firebase/app";
import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);

async function signInWithGoogle() {
  const result = await signInWithPopup(auth, new GoogleAuthProvider());
  const idToken = await result.user.getIdToken();
  // send idToken to your backend to establish a session
}

Backend verification with the Admin SDK:

import { getAuth } from "firebase-admin/auth";

export async function verifyRequest(idToken: string) {
  const decoded = await getAuth().verifyIdToken(idToken);
  return decoded.uid; // verified, trustworthy user ID
}

Core Firebase Auth Concepts Every Developer Should Know

ID tokens are short-lived JWTs, refreshed automatically by the client SDK. Your backend should always verify the token via the Admin SDK on each request rather than trusting a client-provided UID directly — the token is cryptographically signed and verifiable, the raw UID alone is not.

Custom claims attach authorization data directly to the token, avoiding a database lookup for role checks:

import { getAuth } from "firebase-admin/auth";

await getAuth().setCustomUserClaims(uid, { role: "admin" });
// on next token refresh, decoded.role === "admin" is available without a DB query

Firestore security rules mirror the RLS pattern, referencing the authenticated user directly:

match /posts/{postId} {
  allow read, write: if request.auth.uid == resource.data.userId;
}

Session cookies (not just ID tokens) are recommended for server-rendered apps. ID tokens are short-lived and meant for client-side use; the Admin SDK can mint longer-lived session cookies for SSR contexts where you need auth state available on the initial server render, not just after client-side hydration.

Common Firebase Auth Mistakes and How to Fix Them

Mistake 1: trusting a client-sent UID without verifying the ID token. A raw UID string is trivially spoofable — nothing prevents a malicious client from sending someone else's UID directly. Fix: always call verifyIdToken() server-side and use the UID from the verified, decoded token, never from request body/params.

Mistake 2: not refreshing custom claims after setting them. setCustomUserClaims() doesn't retroactively update tokens already issued — the client must force a token refresh (getIdToken(true)) or wait for natural expiry before new claims take effect. Fix: explicitly trigger a refresh right after updating claims if the change needs to apply immediately.

Mistake 3: using ID tokens for long-lived server sessions. ID tokens expire in an hour by design; using them as a persistent session mechanism means constant re-authentication headaches. Fix: use Firebase session cookies (configurable expiry, up to two weeks) for SSR session management instead.

When Should You Use Firebase Auth Instead of Supabase Auth or Clerk?

Use Firebase Auth when you're building on Firestore/Firebase already, need strong phone/SMS auth support, or want Google's broad provider ecosystem. Use Supabase Auth if your database is Postgres and you want the RLS integration instead. Use Clerk when you want pre-built UI components and don't need deep integration with either Firebase or Supabase's database layer.

Firebase Auth in Production

Set custom claims via a Cloud Function trigger on relevant events (like a role change in your admin panel) rather than as a manual one-off script — keeping claims in sync with your actual authorization state is easy to get right at the moment of the change and easy to forget later. Also monitor Firebase Auth quota and SMS costs specifically if using phone auth at scale, since that's the one part of Firebase Auth that isn't fully free.

If you're already deep in the Firebase ecosystem, Firebase Auth's Firestore security rules integration is the same architectural win Supabase Auth offers for Postgres — don't bolt on a separate provider without a specific reason.

Related posts

Written by Suhail Roushan — Full-stack developer. More posts on AI, Next.js, and building products at suhailroushan.com/blog.

Get in touch