Documentation Index
Fetch the complete documentation index at: https://docs.builderbox.ai/llms.txt
Use this file to discover all available pages before exploring further.
Server-Side Setup
1. Configure BetterAuth
// 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),
});
},
},
});
Client-Side Implementation
1. Forgot Password Form
// 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>
);
}
2. Reset Password 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>
);
}
Password Reset Flow
1. Forgot Password Flow
- User clicks “Forgot Password” link
- User enters email address
- System validates email
- Send reset password email
- User receives email with reset link
2. Reset Password Flow
- User clicks reset link in email
- User enters new password
- System validates password
- Update password
- Sign in user with new password
- Redirect to dashboard
Security Features
-
Token Security
- Secure token generation
- Token expiration (1 hour)
- One-time use tokens
- Rate limiting
-
Password Security
- Password complexity requirements
- Password confirmation
- Secure password hashing
- Rate limiting
-
Email Security
- Secure email delivery
- Email verification
- Spam protection
Best Practices
-
Error Handling
- Show user-friendly error messages
- Log password reset attempts
- Handle edge cases
- Provide clear feedback
-
User Experience
- Clear form validation
- Loading states
- Success/error feedback
- Clear instructions
-
Security
- HTTPS in production
- Rate limiting
- Input validation
- Token validation
Common Issues & Solutions
-
Email Not Received
- Check spam folder
- Verify email address
- Check rate limits
- Resend reset email
-
Link Expired
- Request new reset link
- Clear browser cache
- Check system time
- Handle expired tokens
-
Invalid Token
- Request new reset link
- Clear browser cache
- Check URL encoding
- Handle invalid tokens
Next Steps