/** * React Client Components with better-auth * * This example demonstrates: * - useSession hook * - Sign in/up forms * - Social sign-in buttons * - Protected route component * - User profile component * - Organization switcher */ 'use client' import { createAuthClient, useSession } from 'better-auth/client' import { useState, useEffect } from 'react' // Initialize auth client export const authClient = createAuthClient({ baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000' }) // ============================================================================ // Login Form Component // ============================================================================ export function LoginForm() { const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [error, setError] = useState('') const [loading, setLoading] = useState(false) const handleEmailSignIn = async (e: React.FormEvent) => { e.preventDefault() setError('') setLoading(true) try { const { data, error } = await authClient.signIn.email({ email, password }) if (error) { setError(error.message) return } // Redirect on success window.location.href = '/dashboard' } catch (err) { setError('An error occurred. Please try again.') } finally { setLoading(false) } } const handleGoogleSignIn = async () => { setLoading(true) await authClient.signIn.social({ provider: 'google', callbackURL: '/dashboard' }) } const handleGitHubSignIn = async () => { setLoading(true) await authClient.signIn.social({ provider: 'github', callbackURL: '/dashboard' }) } return (

Sign In

{error && (
{error}
)}
setEmail(e.target.value)} required className="w-full px-3 py-2 border rounded-md" placeholder="you@example.com" />
setPassword(e.target.value)} required className="w-full px-3 py-2 border rounded-md" placeholder="••••••••" />
Or continue with

Don't have an account?{' '} Sign up

) } // ============================================================================ // Sign Up Form Component // ============================================================================ export function SignUpForm() { const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [name, setName] = useState('') const [error, setError] = useState('') const [loading, setLoading] = useState(false) const [success, setSuccess] = useState(false) const handleSignUp = async (e: React.FormEvent) => { e.preventDefault() setError('') setLoading(true) try { const { data, error } = await authClient.signUp.email({ email, password, name }) if (error) { setError(error.message) return } setSuccess(true) } catch (err) { setError('An error occurred. Please try again.') } finally { setLoading(false) } } if (success) { return (

Check your email

We've sent a verification link to {email}. Click the link to verify your account.

) } return (

Sign Up

{error && (
{error}
)}
setName(e.target.value)} required className="w-full px-3 py-2 border rounded-md" placeholder="John Doe" />
setEmail(e.target.value)} required className="w-full px-3 py-2 border rounded-md" placeholder="you@example.com" />
setPassword(e.target.value)} required minLength={8} className="w-full px-3 py-2 border rounded-md" placeholder="••••••••" />

At least 8 characters

Already have an account?{' '} Sign in

) } // ============================================================================ // User Profile Component // ============================================================================ export function UserProfile() { const { data: session, isPending } = useSession() if (isPending) { return
Loading...
} if (!session) { return (

Not authenticated

Sign in
) } const handleSignOut = async () => { await authClient.signOut() window.location.href = '/login' } return (
{session.user.image && ( {session.user.name )}

{session.user.name}

{session.user.email}

) } // ============================================================================ // Protected Route Component // ============================================================================ export function ProtectedRoute({ children }: { children: React.ReactNode }) { const { data: session, isPending } = useSession() if (isPending) { return (

Loading...

) } if (!session) { // Redirect to login if (typeof window !== 'undefined') { window.location.href = '/login' } return null } return <>{children} } // ============================================================================ // Organization Switcher Component (if using organizations plugin) // ============================================================================ export function OrganizationSwitcher() { const { data: session } = useSession() const [organizations, setOrganizations] = useState([]) const [loading, setLoading] = useState(true) // Fetch user's organizations useEffect(() => { async function fetchOrgs() { const orgs = await authClient.organization.listUserOrganizations() setOrganizations(orgs) setLoading(false) } fetchOrgs() }, []) const switchOrganization = async (orgId: string) => { await authClient.organization.setActiveOrganization({ organizationId: orgId }) window.location.reload() } if (loading) return
Loading organizations...
return ( ) } // ============================================================================ // 2FA Setup Component (if using twoFactor plugin) // ============================================================================ export function TwoFactorSetup() { const [qrCode, setQrCode] = useState('') const [verifyCode, setVerifyCode] = useState('') const [enabled, setEnabled] = useState(false) const enable2FA = async () => { const { data } = await authClient.twoFactor.enable({ method: 'totp' }) setQrCode(data.qrCode) } const verify2FA = async (e: React.FormEvent) => { e.preventDefault() const { error } = await authClient.twoFactor.verify({ code: verifyCode }) if (!error) { setEnabled(true) } } if (enabled) { return
2FA is enabled!
} if (qrCode) { return (

Scan QR Code

2FA QR Code
setVerifyCode(e.target.value)} placeholder="Enter 6-digit code" className="w-full px-3 py-2 border rounded-md" maxLength={6} />
) } return ( ) }