Implements Firebase Authentication with email, OAuth, phone auth, and custom tokens. Use when building apps with Firebase, needing flexible auth methods, or integrating with Firebase ecosystem.
Implements Firebase Authentication with email, OAuth, phone, and custom tokens for user management.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/admin-sdk.mdreferences/security-rules.mdFirebase Authentication provides backend services and SDKs for user authentication. Supports email/password, OAuth providers, phone, anonymous, and custom token auth.
npm install firebase
// lib/firebase.ts
import { initializeApp, getApps } from 'firebase/app'
import { getAuth } from 'firebase/auth'
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID
}
const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0]
export const auth = getAuth(app)
import { createUserWithEmailAndPassword, updateProfile } from 'firebase/auth'
import { auth } from '@/lib/firebase'
async function signUp(email: string, password: string, displayName: string) {
try {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
await updateProfile(user, { displayName })
return user
} catch (error: any) {
switch (error.code) {
case 'auth/email-already-in-use':
throw new Error('Email already registered')
case 'auth/weak-password':
throw new Error('Password should be at least 6 characters')
default:
throw new Error('Sign up failed')
}
}
}
import { signInWithEmailAndPassword } from 'firebase/auth'
async function signIn(email: string, password: string) {
try {
const { user } = await signInWithEmailAndPassword(auth, email, password)
return user
} catch (error: any) {
switch (error.code) {
case 'auth/invalid-credential':
throw new Error('Invalid email or password')
case 'auth/user-disabled':
throw new Error('Account disabled')
default:
throw new Error('Sign in failed')
}
}
}
import { signOut } from 'firebase/auth'
async function logout() {
await signOut(auth)
}
import { onAuthStateChanged, User } from 'firebase/auth'
// Subscribe to auth state
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
console.log('Signed in:', user.uid)
} else {
console.log('Signed out')
}
})
// Cleanup
unsubscribe()
// contexts/auth-context.tsx
'use client'
import { createContext, useContext, useEffect, useState } from 'react'
import { onAuthStateChanged, User } from 'firebase/auth'
import { auth } from '@/lib/firebase'
type AuthContextType = {
user: User | null
loading: boolean
}
const AuthContext = createContext<AuthContextType>({
user: null,
loading: true
})
export 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>
)
}
export const useAuth = () => useContext(AuthContext)
'use client'
import { useAuth } from '@/contexts/auth-context'
export default function Profile() {
const { user, loading } = useAuth()
if (loading) return <div>Loading...</div>
if (!user) return <div>Please sign in</div>
return (
<div>
<p>Email: {user.email}</p>
<p>Name: {user.displayName}</p>
<img src={user.photoURL || ''} alt="Avatar" />
</div>
)
}
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth'
const googleProvider = new GoogleAuthProvider()
googleProvider.addScope('email')
googleProvider.addScope('profile')
async function signInWithGoogle() {
try {
const result = await signInWithPopup(auth, googleProvider)
const credential = GoogleAuthProvider.credentialFromResult(result)
const token = credential?.accessToken
return result.user
} catch (error: any) {
if (error.code === 'auth/popup-closed-by-user') {
return null
}
throw error
}
}
import { signInWithPopup, GithubAuthProvider } from 'firebase/auth'
const githubProvider = new GithubAuthProvider()
githubProvider.addScope('read:user')
async function signInWithGithub() {
const result = await signInWithPopup(auth, githubProvider)
return result.user
}
For mobile or when popups are blocked:
import { signInWithRedirect, getRedirectResult, GoogleAuthProvider } from 'firebase/auth'
// Initiate redirect
async function startGoogleSignIn() {
await signInWithRedirect(auth, new GoogleAuthProvider())
}
// Handle redirect result (call on page load)
async function handleRedirect() {
const result = await getRedirectResult(auth)
if (result) {
console.log('Signed in:', result.user)
}
}
import { signInWithPhoneNumber, RecaptchaVerifier } from 'firebase/auth'
// Setup reCAPTCHA
const recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
size: 'invisible',
callback: () => {
// reCAPTCHA solved
}
})
async function sendVerificationCode(phoneNumber: string) {
try {
const confirmationResult = await signInWithPhoneNumber(
auth,
phoneNumber,
recaptchaVerifier
)
// Store confirmationResult to use in verification step
return confirmationResult
} catch (error) {
console.error('SMS not sent:', error)
throw error
}
}
async function verifyCode(confirmationResult: any, code: string) {
try {
const result = await confirmationResult.confirm(code)
return result.user
} catch (error) {
throw new Error('Invalid verification code')
}
}
import { signInAnonymously, linkWithCredential, EmailAuthProvider } from 'firebase/auth'
// Sign in anonymously
async function signInAnon() {
const { user } = await signInAnonymously(auth)
return user
}
// Convert to permanent account
async function convertToEmailAccount(email: string, password: string) {
const user = auth.currentUser
if (!user) throw new Error('No user')
const credential = EmailAuthProvider.credential(email, password)
await linkWithCredential(user, credential)
}
import { sendPasswordResetEmail } from 'firebase/auth'
async function resetPassword(email: string) {
await sendPasswordResetEmail(auth, email, {
url: 'https://myapp.com/login'
})
}
import { updatePassword, reauthenticateWithCredential, EmailAuthProvider } from 'firebase/auth'
async function changePassword(currentPassword: string, newPassword: string) {
const user = auth.currentUser
if (!user || !user.email) throw new Error('No user')
// Re-authenticate first
const credential = EmailAuthProvider.credential(user.email, currentPassword)
await reauthenticateWithCredential(user, credential)
// Update password
await updatePassword(user, newPassword)
}
import { sendEmailVerification } from 'firebase/auth'
async function verifyEmail() {
const user = auth.currentUser
if (!user) throw new Error('No user')
await sendEmailVerification(user, {
url: 'https://myapp.com/verified'
})
}
// Check if verified
const isVerified = auth.currentUser?.emailVerified
import { updateProfile, updateEmail } from 'firebase/auth'
async function updateUserProfile(displayName: string, photoURL: string) {
const user = auth.currentUser
if (!user) throw new Error('No user')
await updateProfile(user, { displayName, photoURL })
}
async function changeEmail(newEmail: string) {
const user = auth.currentUser
if (!user) throw new Error('No user')
await updateEmail(user, newEmail)
// Sends verification email automatically
}
async function getIdToken() {
const user = auth.currentUser
if (!user) throw new Error('No user')
const token = await user.getIdToken()
return token
}
// Force refresh
const token = await user.getIdToken(true)
// Server-side (Firebase Admin SDK)
import { getAuth } from 'firebase-admin/auth'
async function verifyToken(idToken: string) {
try {
const decodedToken = await getAuth().verifyIdToken(idToken)
return decodedToken
} catch (error) {
throw new Error('Invalid token')
}
}
import { getAuth } from 'firebase-admin/auth'
async function setUserRole(uid: string, role: string) {
await getAuth().setCustomUserClaims(uid, { role })
}
async function getUserRole() {
const user = auth.currentUser
if (!user) return null
const tokenResult = await user.getIdTokenResult()
return tokenResult.claims.role
}
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const session = request.cookies.get('session')
if (!session && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*']
}
// app/api/session/route.ts
import { getAuth } from 'firebase-admin/auth'
import { cookies } from 'next/headers'
export async function POST(request: Request) {
const { idToken } = await request.json()
const expiresIn = 60 * 60 * 24 * 5 * 1000 // 5 days
try {
const sessionCookie = await getAuth().createSessionCookie(idToken, {
expiresIn
})
cookies().set('session', sessionCookie, {
maxAge: expiresIn / 1000,
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
path: '/'
})
return Response.json({ status: 'success' })
} catch (error) {
return Response.json({ error: 'Unauthorized' }, { status: 401 })
}
}
import { linkWithPopup, GoogleAuthProvider } from 'firebase/auth'
async function linkGoogle() {
const user = auth.currentUser
if (!user) throw new Error('No user')
const result = await linkWithPopup(user, new GoogleAuthProvider())
return result.user
}
// Unlink provider
import { unlink } from 'firebase/auth'
async function unlinkGoogle() {
const user = auth.currentUser
if (!user) throw new Error('No user')
await unlink(user, 'google.com')
}
import { AuthError } from 'firebase/auth'
function handleAuthError(error: AuthError) {
switch (error.code) {
case 'auth/email-already-in-use':
return 'Email already registered'
case 'auth/invalid-email':
return 'Invalid email address'
case 'auth/weak-password':
return 'Password too weak'
case 'auth/user-not-found':
return 'User not found'
case 'auth/wrong-password':
return 'Incorrect password'
case 'auth/too-many-requests':
return 'Too many attempts. Try again later'
case 'auth/network-request-failed':
return 'Network error'
default:
return 'Authentication error'
}
}
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.