Skip to main content

Verification Flow

1

User signs up

A record is created in the user collection with emailVerified: false. Profile data is saved to the temporary userprofile collection.
2

Verification email sent

Better Auth generates a token stored in the verification collection and sends an email with a verification link.
3

User clicks the link

The link hits GET /api/auth/verify-email?token=...&callbackURL=/. Better Auth validates the token and sets emailVerified: true.
4

Welcome email triggered

The onEmailVerification callback fires, sends an Inngest event to trigger the welcome email, and cleans up the temporary profile data.
5

User can sign in

With emailVerified: true, the user can now authenticate normally.
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 in lib/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 in lib/nodemailer/templates.ts with:
  • Gold/yellow CTA button matching the brand
  • 24-hour expiry notice
  • Mobile-responsive layout
  • Dark mode support
All URLs in templates use the {{baseUrl}} placeholder, which is replaced at runtime with NEXT_PUBLIC_BASE_URL.

Database

It’s normal for the verification collection to appear empty after a user verifies. Tokens are ephemeral and deleted once consumed.

Testing

  1. Run npm run dev and sign up
  2. Copy the verification URL from the terminal logs:
  1. Paste the URL in your browser
  2. You should see “Email Verified!” and be redirected to sign-in