The boilerplate provides a complete password reset flow with forgot password and reset password functionality.
// apps/server/src/lib/auth.ts import { betterAuth } from "better-auth"; import { prismaAdapter } from "better-auth/adapters/prisma"; export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: "postgresql", }), emailAndPassword: { enabled: true, sendResetPassword: async ({ user, url, token }) => { const userName = user?.name || user?.email?.split("@")[0] || "User"; await sendEmail({ to: user.email, subject: "Reset your password", from: "onboarding@resend.dev", html: getResetPasswordEmailHtml(userName, url), }); }, }, });
// apps/web/src/features/auth/forgot-password-form.tsx "use client"; import { authClient } from "@/lib/auth-client"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; const forgotPasswordSchema = z.object({ email: z.string().email(), }); export function ForgotPasswordForm() { const form = useForm({ resolver: zodResolver(forgotPasswordSchema), }); const onSubmit = async (data: z.infer<typeof forgotPasswordSchema>) => { try { await authClient.resetPassword(data.email); // Handle success } catch (error) { // Handle error } }; return ( <form onSubmit={form.handleSubmit(onSubmit)}> {/* Form fields */} </form> ); }
// apps/web/src/features/auth/reset-password-form.tsx "use client"; import { authClient } from "@/lib/auth-client"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; const resetPasswordSchema = z.object({ password: z.string().min(8), confirmPassword: z.string(), }).refine((data) => data.password === data.confirmPassword, { message: "Passwords don't match", path: ["confirmPassword"], }); export function ResetPasswordForm() { const form = useForm({ resolver: zodResolver(resetPasswordSchema), }); const onSubmit = async (data: z.infer<typeof resetPasswordSchema>) => { try { await authClient.resetPassword(data.password); // Handle success } catch (error) { // Handle error } }; return ( <form onSubmit={form.handleSubmit(onSubmit)}> {/* Form fields */} </form> ); }