1Firebase Project Setup
- Create a project at Firebase Console
- Click Authentication → Get started
- Enable desired sign-in methods:
- Email/Password
- GitHub (OAuth setup required)
- Project settings → General → Add web app
- Copy the Firebase configuration
2React App Integration
Terminal
npm install firebaseEnvironment Variables
.env.local
# .env.local
VITE_FIREBASE_API_KEY=xxx
VITE_FIREBASE_AUTH_DOMAIN=your-app.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your-app
VITE_FIREBASE_STORAGE_BUCKET=your-app.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=xxx
VITE_FIREBASE_APP_ID=xxxFirebase Initialization
lib/firebase.ts
// lib/firebase.ts
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);3Email/Password Authentication
components/EmailAuth.tsx
// components/EmailAuth.tsx
import { useState } from 'react';
import {
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
} from 'firebase/auth';
import { auth } from '../lib/firebase';
export function EmailAuth() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [isLogin, setIsLogin] = useState(true);
const [error, setError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
try {
if (isLogin) {
await signInWithEmailAndPassword(auth, email, password);
} else {
await createUserWithEmailAndPassword(auth, email, password);
}
} catch (err: any) {
setError(err.message);
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
className="w-full px-4 py-2 border rounded-lg"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password (min 6 characters)"
className="w-full px-4 py-2 border rounded-lg"
required
minLength={6}
/>
{error && <p className="text-red-500 text-sm">{error}</p>}
<button
type="submit"
className="w-full py-2 bg-blue-600 text-white rounded-lg"
>
{isLogin ? 'Sign In' : 'Sign Up'}
</button>
<button
type="button"
onClick={() => setIsLogin(!isLogin)}
className="w-full text-sm text-gray-600"
>
{isLogin ? "Don't have an account? Sign Up" : 'Already have an account? Sign In'}
</button>
</form>
);
}4Google Social Login
components/GoogleLogin.tsx
// components/GoogleLogin.tsx
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
import { auth } from '../lib/firebase';
const googleProvider = new GoogleAuthProvider();
export function GoogleLogin() {
const handleGoogleLogin = async () => {
try {
const result = await signInWithPopup(auth, googleProvider);
// User info in result.user
console.log('Login successful:', result.user);
} catch (error: any) {
console.error('Login failed:', error.message);
}
};
return (
<button
onClick={handleGoogleLogin}
className="flex items-center gap-2 px-4 py-2 bg-white border rounded-lg"
>
<svg className="w-5 h-5" viewBox="0 0 24 24">
<path
fill="#4285F4"
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
/>
<path
fill="#34A853"
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
/>
<path
fill="#FBBC05"
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
/>
<path
fill="#EA4335"
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
/>
</svg>
Continue with Google
</button>
);
}Info
You must first enable Google Sign-In in Firebase Console. Other providers like GitHub and Facebook can be added in a similar way.
5Auth State Management (Custom Hook)
Use onAuthStateChanged to detect changes in login state.
hooks/useAuth.ts
// hooks/useAuth.ts
import { useState, useEffect } from 'react';
import { User, onAuthStateChanged, signOut } from 'firebase/auth';
import { auth } from '../lib/firebase';
export function useAuth() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setUser(user);
setLoading(false);
});
// Unsubscribe on component unmount
return () => unsubscribe();
}, []);
const logout = async () => {
await signOut(auth);
};
return {
user,
loading,
isAuthenticated: !!user,
logout,
};
}Global State with Context
contexts/AuthContext.tsx
// contexts/AuthContext.tsx
import { createContext, useContext, ReactNode } from 'react';
import { User } from 'firebase/auth';
import { useAuth } from '../hooks/useAuth';
interface AuthContextType {
user: User | null;
loading: boolean;
isAuthenticated: boolean;
logout: () => Promise<void>;
}
const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: ReactNode }) {
const auth = useAuth();
return (
<AuthContext.Provider value={auth}>
{children}
</AuthContext.Provider>
);
}
export function useAuthContext() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuthContext must be used within AuthProvider');
}
return context;
}
// Usage in main.tsx
// <AuthProvider>
// <App />
// </AuthProvider>6Protected Route Implementation
components/ProtectedRoute.tsx
// components/ProtectedRoute.tsx
import { Navigate } from 'react-router-dom';
import { useAuthContext } from '../contexts/AuthContext';
interface ProtectedRouteProps {
children: React.ReactNode;
}
export function ProtectedRoute({ children }: ProtectedRouteProps) {
const { isAuthenticated, loading } = useAuthContext();
if (loading) {
return <div>Loading...</div>;
}
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <>{children}</>;
}
// Usage example
// <Route
// path="/dashboard"
// element={
// <ProtectedRoute>
// <Dashboard />
// </ProtectedRoute>
// }
// />User Profile Display
components/UserProfile.tsx
// components/UserProfile.tsx
import { useAuthContext } from '../contexts/AuthContext';
export function UserProfile() {
const { user, logout, isAuthenticated } = useAuthContext();
if (!isAuthenticated) {
return null;
}
return (
<div className="flex items-center gap-4 p-4 bg-white rounded-lg shadow">
{user?.photoURL && (
<img
src={user.photoURL}
alt={user.displayName || 'Profile'}
className="w-12 h-12 rounded-full"
/>
)}
<div>
<p className="font-bold">{user?.displayName || 'User'}</p>
<p className="text-sm text-gray-600">{user?.email}</p>
</div>
<button
onClick={logout}
className="ml-auto px-4 py-2 bg-red-600 text-white rounded-lg"
>
Sign Out
</button>
</div>
);
}When Should You Choose Firebase Auth?
Firebase Auth Recommended
- Already using Firebase ecosystem (Firestore, etc.)
- Developing web + mobile simultaneously
- Need unlimited free users
- Google Sign-In is the primary method
Next Steps
- Phone Authentication - Add SMS verification
- User Management - Profile updates, password reset
- Firestore Integration - Store per-user data