Verification Flow
User signs up
A record is created in the
user collection with emailVerified: false. Profile data is saved to the temporary userprofile collection.Verification email sent
Better Auth generates a token stored in the
verification collection and sends an email with a verification link.User clicks the link
The link hits
GET /api/auth/verify-email?token=...&callbackURL=/. Better Auth validates the token and sets emailVerified: true.Welcome email triggered
The
onEmailVerification callback fires, sends an Inngest event to trigger the welcome email, and cleans up the temporary profile data.In development (
NODE_ENV=development), email verification is disabled. Users are auto signed-in after signup and verification URLs are logged to the console instead of emailed.Configuration
Email verification is configured inlib/better-auth/auth.ts:
Important: GET Not POST
The verification endpoint uses GET with query parameters, not POST with a JSON body.Email Template
The verification email uses a styled HTML template defined inlib/nodemailer/templates.ts with:
- Gold/yellow CTA button matching the brand
- 24-hour expiry notice
- Mobile-responsive layout
- Dark mode support
{{baseUrl}} placeholder, which is replaced at runtime with NEXT_PUBLIC_BASE_URL.
Database
| Collection | Role |
|---|---|
user | emailVerified field updated to true after verification |
verification | Stores ephemeral tokens — deleted after use |
userprofile | Temporary sign-up data — deleted after verification triggers welcome email |
It’s normal for the
verification collection to appear empty after a user verifies. Tokens are ephemeral and deleted once consumed.Testing
- Development
- Production
- Run
npm run devand sign up - Copy the verification URL from the terminal logs:
- Paste the URL in your browser
- You should see “Email Verified!” and be redirected to sign-in