Firebase Auth
Build with Firebase Authentication for user sign-in. Use this skill when the
You are an auth specialist who integrates Firebase Authentication into projects.
Firebase Auth provides drop-in authentication with email/password, social
providers, phone auth, and anonymous auth — with client SDKs and server-side
token verification via the Admin SDK.
## Key Points
- Use `onAuthStateChanged` for reactive auth state — don't check `currentUser` directly on load
- Verify ID tokens server-side for API routes — never trust client-side auth alone
- Use custom claims for authorization (admin, plan, roles) — they're embedded in the token
- Force token refresh after setting custom claims — tokens are cached for up to 1 hour
- Use `signInWithRedirect` on mobile — popups are blocked on many mobile browsers
- Clean up auth state listeners in useEffect return functions
- Trusting `auth.currentUser` on page load — it's null until auth initializes
- Not verifying ID tokens server-side — client tokens can be spoofed
- Storing sensitive data in custom claims — they're visible in the JWT
- Using custom claims for frequently changing data — token refresh is needed
- Not handling the loading state — auth state takes a moment to initialize
- Creating custom session management when Firebase handles token refresh
## Quick Example
```bash
npm install firebase
npm install firebase-admin # Server-side
```
```typescript
import { signOut } from 'firebase/auth';
await signOut(auth);
```skilldb get auth-services-skills/Firebase AuthFull skill: 234 linesFirebase Authentication Integration
You are an auth specialist who integrates Firebase Authentication into projects. Firebase Auth provides drop-in authentication with email/password, social providers, phone auth, and anonymous auth — with client SDKs and server-side token verification via the Admin SDK.
Core Philosophy
Client-side first
Firebase Auth runs primarily on the client. The SDK handles the OAuth flows, token refresh, and auth state persistence. Your server verifies ID tokens but doesn't manage sessions — Firebase handles that automatically.
Provider-agnostic
Firebase Auth supports email/password, Google, Apple, GitHub, Twitter, Facebook, phone OTP, and anonymous auth through a consistent API. Adding a provider is enabling it in the console and adding a few lines of code.
Custom claims for authorization
Firebase Auth handles authentication (who is this user). For authorization (what
can they do), set custom claims on the user token — admin, plan, orgId —
and check them client-side or in security rules.
Setup
Install
npm install firebase
npm install firebase-admin # Server-side
Initialize (client)
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
const app = initializeApp({
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
});
export const auth = getAuth(app);
Initialize (server)
import { initializeApp, cert } from 'firebase-admin/app';
import { getAuth } from 'firebase-admin/auth';
const app = initializeApp({
credential: cert({
projectId: process.env.FIREBASE_PROJECT_ID,
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
}),
});
export const adminAuth = getAuth(app);
Key Techniques
Email/password auth
import { createUserWithEmailAndPassword, signInWithEmailAndPassword, updateProfile } from 'firebase/auth';
// Sign up
const { user } = await createUserWithEmailAndPassword(auth, email, password);
await updateProfile(user, { displayName: name });
// Sign in
const { user } = await signInWithEmailAndPassword(auth, email, password);
// Password reset
import { sendPasswordResetEmail } from 'firebase/auth';
await sendPasswordResetEmail(auth, email);
OAuth providers
import {
signInWithPopup, signInWithRedirect, getRedirectResult,
GoogleAuthProvider, GithubAuthProvider, OAuthProvider
} from 'firebase/auth';
// Google
const googleProvider = new GoogleAuthProvider();
const { user } = await signInWithPopup(auth, googleProvider);
// GitHub
const githubProvider = new GithubAuthProvider();
const { user } = await signInWithPopup(auth, githubProvider);
// Apple
const appleProvider = new OAuthProvider('apple.com');
appleProvider.addScope('email');
const { user } = await signInWithPopup(auth, appleProvider);
// Redirect flow (mobile-friendly)
await signInWithRedirect(auth, googleProvider);
// On page load:
const result = await getRedirectResult(auth);
if (result) {
const user = result.user;
}
Auth state listener
import { onAuthStateChanged, type User } from 'firebase/auth';
// React context pattern
function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
return (
<AuthContext.Provider value={{ user, loading }}>
{children}
</AuthContext.Provider>
);
}
ID token verification (server-side)
// API route — verify Firebase ID token
export async function GET(req: Request) {
const authHeader = req.headers.get('authorization');
if (!authHeader?.startsWith('Bearer ')) {
return new Response('Unauthorized', { status: 401 });
}
const token = authHeader.split('Bearer ')[1];
try {
const decoded = await adminAuth.verifyIdToken(token);
const userId = decoded.uid;
const data = await db.query.posts.findMany({
where: eq(posts.authorId, userId),
});
return Response.json(data);
} catch {
return new Response('Invalid token', { status: 401 });
}
}
// Client-side — send token with requests
const token = await auth.currentUser?.getIdToken();
const res = await fetch('/api/posts', {
headers: { Authorization: `Bearer ${token}` },
});
Custom claims
// Server-side: set custom claims
await adminAuth.setCustomUserClaims(userId, {
admin: true,
plan: 'pro',
orgId: 'org_123',
});
// Client-side: read custom claims
const token = await auth.currentUser?.getIdTokenResult();
const isAdmin = token?.claims.admin === true;
const plan = token?.claims.plan as string;
// Force token refresh to get updated claims
await auth.currentUser?.getIdToken(true);
Phone auth
import { signInWithPhoneNumber, RecaptchaVerifier } from 'firebase/auth';
// Set up reCAPTCHA
const recaptcha = new RecaptchaVerifier(auth, 'recaptcha-container', {
size: 'invisible',
});
// Send verification code
const confirmationResult = await signInWithPhoneNumber(auth, '+1234567890', recaptcha);
// Verify code
const { user } = await confirmationResult.confirm(userEnteredCode);
Sign out
import { signOut } from 'firebase/auth';
await signOut(auth);
Best Practices
- Use
onAuthStateChangedfor reactive auth state — don't checkcurrentUserdirectly on load - Verify ID tokens server-side for API routes — never trust client-side auth alone
- Use custom claims for authorization (admin, plan, roles) — they're embedded in the token
- Force token refresh after setting custom claims — tokens are cached for up to 1 hour
- Use
signInWithRedirecton mobile — popups are blocked on many mobile browsers - Clean up auth state listeners in useEffect return functions
Anti-Patterns
- Trusting
auth.currentUseron page load — it's null until auth initializes - Not verifying ID tokens server-side — client tokens can be spoofed
- Storing sensitive data in custom claims — they're visible in the JWT
- Using custom claims for frequently changing data — token refresh is needed
- Not handling the loading state — auth state takes a moment to initialize
- Creating custom session management when Firebase handles token refresh
Install this skill directly: skilldb add auth-services-skills
Related Skills
Auth0
Build with Auth0 for enterprise authentication and identity. Use this skill when
Clerk
Build with Clerk for authentication and user management. Use this skill when the
Cognito
Build with Amazon Cognito for authentication and user management. Use this skill
Descope
Integrate Descope to add secure, no-code/low-code authentication and user management to your applications.
Hanko
Integrate Hanko for modern, passwordless authentication in your web applications.
Kinde
Build with Kinde for authentication and user management. Use this skill when the