A complete authentication starter template with Better Auth, Prisma ORM, and Neon PostgreSQL.
- ✅ Email/Password authentication with email verification (OTP)
- ✅ Google OAuth integration
- ✅ Protected routes (middleware + page-level)
- ✅ Prisma ORM with Neon PostgreSQL
- ✅ React Hook Form + Zod validation
- ✅ shadcn/ui components
- ✅ Custom fonts (Inter for headings, JetBrains Mono for body)
```bash npm install ```
Copy .env.example to .env.local and fill in the values:
```bash cp .env.example .env.local ```
Required Environment Variables:
NEON_NEON_DATABASE_URL- Paste Your UrlBETTER_AUTH_SECRET- Generate with:openssl rand -base64 32GOOGLE_CLIENT_ID- Get from Google Cloud ConsoleGOOGLE_CLIENT_SECRET- Get from Google Cloud ConsoleRESEND_API_KEY- Get from ResendEMAIL_FROM- Your verified sender email in Resend
- Go to Google Cloud Console
- Create a new project or select existing
- Enable Google+ API
- Go to "Credentials" → "Create Credentials" → "OAuth 2.0 Client ID"
- Add authorized redirect URI:
http://localhost:3000/api/auth/callback/google - Copy Client ID and Client Secret to
.env.local
- Sign up at Resend
- Verify your domain or use their test domain
- Create an API key
- Add to
.env.local
```bash
npm run db:generate
npm run db:push ```
```bash npm run dev ```
Visit http://localhost:3000/signup to test the authentication flow.
- User enters email/password → submits form
- Better Auth creates unverified user
- OTP sent to email via Resend
- User redirected to
/verify-email - User enters OTP → account verified → redirect to
/dashboard
- User enters credentials or clicks Google
- Better Auth validates
- Redirect to
/dashboardif verified - Redirect to
/verify-emailif unverified
- User clicks "Sign in with Google"
- OAuth popup/redirect
- Better Auth handles callback
- Auto-verified → redirect to
/dashboard
This template implements dual-layer protection:
-
Middleware Protection (
middleware.ts)- Checks authentication at the edge
- Redirects unauthenticated users before page loads
-
Page-Level Protection (
app/dashboard/page.tsx)- Server-side session check in page component
- Additional security layer
- Prevents unauthorized access even if middleware is bypassed
``` ├── app/ │ ├── api/auth/[...all]/route.ts # Auth API handler │ ├── signup/page.tsx # Signup page │ ├── login/page.tsx # Login page │ ├── verify-email/page.tsx # OTP verification │ └── dashboard/page.tsx # Protected dashboard ├── components/ │ └── auth/ │ ├── signup-form.tsx # Signup form component │ ├── login-form.tsx # Login form component │ └── verify-email-form.tsx # OTP verification form ├── lib/ │ ├── auth.ts # Better Auth config │ ├── auth-client.ts # Client-side auth utilities │ ├── auth-guard.tsx # Client-side auth guard │ └── prisma.ts # Prisma client ├── prisma/ │ └── schema.prisma # Database schema └── middleware.ts # Route protection ```
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run db:generate- Generate Prisma clientnpm run db:push- Push schema to databasenpm run db:studio- Open Prisma Studio
- Framework: Next.js 16
- Auth: Better Auth 1.1+
- Database: Neon PostgreSQL
- ORM: Prisma 6+
- Email: Resend
- Forms: React Hook Form + Zod
- UI: shadcn/ui + Tailwind CSS v4
- Fonts: Inter (headings) + JetBrains Mono (body)