Last Updated: December 4, 2025
Status: ACTIVE
⚠️ IMPORTANT: For the Firebase REST API implementation that handles token verification in production (solving the jose dependency issue), see Firebase REST API Architecture.
This document describes the ONLY authentication system that should be used in WeWrite. The complex multi-auth system has been replaced with a clean, reliable Firebase Auth implementation.
WeWrite uses a clean authentication architecture that provides:
- AuthProvider - Single authentication provider using Firebase Auth
- Firebase Auth - Standard Firebase authentication
- Session Cookies - Session management for middleware compatibility
This architecture provides:
- Clean, reliable authentication
- Standard Firebase Auth features
- Easy maintenance and debugging
- Single source of truth for authentication state
- Better performance and reliability
Purpose: Manages user authentication using standard Firebase Auth.
Key Features:
- Single user authentication
- Firebase Auth integration
- Session state management
- Automatic token refresh
Exports:
export const useAuth = (): AuthContextValueContext Value:
interface AuthContextValue {
user: User | null;
isLoading: boolean;
isAuthenticated: boolean;
error: string | null;
signIn: (email: string, password: string) => Promise<void>;
signOut: () => Promise<void>;
refreshUser: () => Promise<void>;
updateProfile: (updates: Partial<User>) => Promise<void>;
clearError: () => void;
}Usage Examples:
// Basic auth check
const { user, isAuthenticated, isLoading } = useAuth();
// Email verification check
const isEmailVerified = user?.emailVerified ?? false;
// User data access
const userId = user?.uid;
const userEmail = user?.email;Purpose: Standard Firebase Authentication integration.
Key Features:
- Email/password authentication
- User registration and login
- Password reset functionality
- Automatic session management
Firebase Auth Methods:
// Registration
createUserWithEmailAndPassword(auth, email, password)
// Login
signInWithEmailAndPassword(auth, email, password)
// Logout
signOut(auth)
// Password Reset
sendPasswordResetEmail(auth, email)Purpose: Simple session cookies for middleware compatibility with device tracking.
Key Features:
- HTTP-only session cookies
- Automatic cookie management
- Middleware authentication
- Server-side session validation
- Device tracking and management
- Multi-device session support
Cookie Structure:
interface SessionCookie {
uid: string;
email: string;
username: string;
emailVerified: boolean;
}Purpose: Manage user authentication sessions with Firebase Auth integration.
Key Features:
- Session Persistence: Automatic session persistence via Firebase Auth
- Cookie Management: HTTP-only session cookies for middleware compatibility
- Session Validation: Server-side session validation for protected routes
- Automatic Cleanup: Session expiration and cleanup handling
Device Information Structure:
interface DeviceInfo {
userAgent: string;
platform: string;
browser: string;
os: string;
deviceType: 'desktop' | 'mobile' | 'tablet';
location?: string;
}
interface UserSession {
id: string;
userId: string;
deviceInfo: DeviceInfo;
createdAt: string;
lastActiveAt: string;
ipAddress: string;
isCurrentSession: boolean;
}API Endpoints:
GET /api/auth/sessions- List all active sessions for current userDELETE /api/auth/sessions/[sessionId]- Revoke specific session/device
## Provider Hierarchy
```tsx
// app/layout.tsx
<AuthProvider>
{/* Rest of app */}
</AuthProvider>
Critical: This is the ONLY authentication provider that should be used. The complex multi-auth system has been removed.
import { useAuth } from '../providers/AuthProvider';
function MyComponent() {
const { user, isAuthenticated, isLoading } = useAuth();
if (isLoading) return <LoadingSpinner />;
if (!isAuthenticated) return <LoginPrompt />;
return <div>Welcome, {user.username}!</div>;
}import { useAuth } from '../providers/AuthProvider';
function AuthComponent() {
const { signIn, signOut } = useAuth();
const handleLogin = async (email: string, password: string) => {
try {
await signIn(email, password);
} catch (error) {
console.error('Sign in failed:', error);
}
};
const handleLogout = async () => {
try {
await signOut();
} catch (error) {
console.error('Sign out failed:', error);
}
};
return (
<div>
{/* Login/Register/Logout UI */}
</div>
);
}import { useAuth } from '../providers/SimpleAuthProvider';
function AdminComponent() {
const { user } = useAuth();
const isAdmin = user?.email === 'jamiegray2234@gmail.com';
if (!isAdmin) {
return <div>Access denied</div>;
}
return <div>Admin panel content</div>;
}Access authentication state through the useAuth hook:
import { useAuth } from '../providers/AuthProvider';
function MyComponent() {
const { user, isAuthenticated, isLoading } = useAuth();
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) return <div>Please log in</div>;
return <div>Welcome, {user.username}!</div>;
}Protect routes by checking authentication status:
import { useAuth } from '../providers/AuthProvider';
import { useRouter } from 'next/navigation';
function ProtectedPage() {
const { isAuthenticated, isLoading } = useAuth();
const router = useRouter();
useEffect(() => {
if (!isLoading && !isAuthenticated) {
router.push('/auth/login');
}
}, [isAuthenticated, isLoading, router]);
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) return null;
return <div>Protected content</div>;
}Security Benefits:
- Users can see if unknown devices are logged in
- Ability to remotely log out compromised devices
- Clear visibility into account access patterns
- Enhanced security through session monitoring
Session Creation: Sessions are automatically created when users log in Session Updates: Last activity is updated on each authenticated request Session Cleanup: Expired sessions are automatically cleaned up Current Session Detection: Uses session cookies to identify current device
- Use
useAuth()hook for all authentication needs - Check
isLoadingbefore rendering auth-dependent content - Handle authentication errors gracefully
- Check
isAuthenticatedbefore rendering protected content - Redirect to login page for unauthenticated users
- Show loading states during authentication checks
- Wrap auth operations in try-catch blocks
- Display user-friendly error messages
- Log errors for debugging
- Firebase Auth handles session persistence automatically
- Session cookies provide middleware compatibility
- No manual session management required
- Implement proper session timeout handling
- Use secure HTTP-only cookies
- Validate sessions on protected routes
- Handle session expiration gracefully
The complex multi-auth system has been replaced with clean Firebase Auth:
- ❌
MultiAuthProvider- No longer needed - ❌
CurrentAccountProvider- Replaced withAuthProvider - ❌
SessionStore- No longer needed - ❌ Account switching - Single user authentication only
- ✅
AuthProvider- Single authentication provider - ✅
useAuth()- Authentication hook - ✅ Firebase Auth - Standard Firebase authentication
- ✅ Session cookies - Session management
- Replace
useCurrentAccount()withuseAuth() - Update component props from
sessiontouser - Remove account switching functionality
- Clean authentication logic
- Update documentation and tests
Firebase Auth → SimpleAuthProvider → Components
↓
Session Cookies (for middleware)
- User logs in through Firebase Auth
- AuthProvider manages auth state
- Session cookies created for middleware compatibility
- Device information is captured and stored
- Session tracking begins for the new device
- Components access auth state via
useAuth()hook
- User logs in through Firebase Auth
- Session cookie is created for middleware compatibility
- Session is validated on protected routes
- Session expires automatically or on logout
- Expired sessions redirect to login page
The simplified authentication system provides:
- ✅ Reliability - Standard Firebase Auth implementation
- ✅ Maintainability - Single authentication provider
- ✅ Performance - Reduced complexity and overhead
- ✅ Security - Firebase Auth security features
- ✅ Simplicity - Easy to understand and debug
- ✅ Session Management - Proper session handling with cookies
- ✅ Middleware Compatibility - Works with Next.js middleware
This architecture replaces the complex multi-auth system with a simple, reliable solution that meets all authentication needs with clean session management.
- Firebase Auth triggers authentication state changes
- SimpleAuthProvider receives auth changes and updates user state
- Components consume auth data via
useAuth() - Session cookies provide middleware compatibility
interface User {
uid: string;
email: string;
username: string;
photoURL?: string;
emailVerified: boolean;
username?: string;
}Last Updated: December 4, 2025 Maintainer: WeWrite Development Team Status: ACTIVE - This is the current simplified authentication system
In production (Vercel serverless), token verification uses the Firebase REST API instead of Firebase Admin Auth to avoid jose dependency issues:
// Server-side session creation (api/auth/session/route.ts)
import { verifyIdToken } from '../../../lib/firebase-rest';
import { getFirebaseAdmin } from '../../../firebase/firebaseAdmin';
// 1. Verify token with REST API (avoids jose error)
const verifyResult = await verifyIdToken(idToken);
if (!verifyResult.success) {
return NextResponse.json({ error: 'Invalid token' }, { status: 401 });
}
// 2. Get user data with Admin Firestore (works fine)
const admin = getFirebaseAdmin();
const userDoc = await admin.firestore()
.collection('users')
.doc(verifyResult.uid)
.get();
// 3. Create session cookie
const sessionData = {
uid: verifyResult.uid,
email: verifyResult.email,
username: userDoc.data()?.username
};
response.cookies.set('simpleUserSession', JSON.stringify(sessionData), {
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 14 // 14 days
});See Firebase REST API Architecture for full details.
- Firebase REST API Architecture - START HERE for production auth implementation
- Authentication Architecture - Auth system overview
- Environment Quick Reference - Environment behavior