2 min readLast updated: 2025-12-31 12:12

Authentication

This template uses Better Auth for authentication, providing a secure and flexible authentication system.

Features

  • Email/Password - Traditional email and password authentication
  • Social Login - OAuth providers (Google, GitHub, etc.)
  • Magic Links - Passwordless email authentication
  • Two-Factor Authentication - Enhanced security with 2FA
  • Session Management - Secure session handling

Configuration

Environment Variables

Add the following to your .env.local:

# Better Auth Configuration
BETTER_AUTH_SECRET="your-secret-key-min-32-chars"
BETTER_AUTH_URL="http://localhost:3000"

# OAuth Providers (optional)
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"

GITHUB_CLIENT_ID="your-github-client-id"
GITHUB_CLIENT_SECRET="your-github-client-secret"

Auth Configuration

The authentication configuration is located in src/lib/auth.ts:

import { betterAuth } from 'better-auth'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { db } from './database'

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: 'pg', // or 'sqlite'
  }),
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    },
  },
})

Usage

Client-Side Authentication

Use the auth client in your React components:

'use client'

import { useSession, signIn, signOut } from '@/lib/auth-client'

export function AuthButton() {
  const { data: session, isPending } = useSession()

  if (isPending) {
    return <div>Loading...</div>
  }

  if (session) {
    return (
      <div>
        <p>Welcome, {session.user.name}!</p>
        <button onClick={() => signOut()}>Sign Out</button>
      </div>
    )
  }

  return (
    <button onClick={() => signIn.email({ email, password })}>
      Sign In
    </button>
  )
}

Server-Side Authentication

Check authentication in Server Components:

import { auth } from '@/lib/auth'
import { headers } from 'next/headers'

export default async function ProtectedPage() {
  const session = await auth.api.getSession({
    headers: await headers(),
  })

  if (!session) {
    redirect('/login')
  }

  return <div>Protected content for {session.user.name}</div>
}

API Route Protection

Protect your API routes:

import { auth } from '@/lib/auth'
import { headers } from 'next/headers'
import { NextResponse } from 'next/server'

export async function GET() {
  const session = await auth.api.getSession({
    headers: await headers(),
  })

  if (!session) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
  }

  return NextResponse.json({ data: 'Protected data' })
}

Customization

Custom Login Page

Create a custom login page at src/app/[lang]/(auth)/login/page.tsx:

import { LoginForm } from '@/components/auth/LoginForm'

export default function LoginPage() {
  return (
    <div className="min-h-screen flex items-center justify-center">
      <LoginForm />
    </div>
  )
}

Email Templates

Customize email templates in src/lib/email/templates/:

  • verification.tsx - Email verification
  • password-reset.tsx - Password reset
  • magic-link.tsx - Magic link login

Security Best Practices

  1. Use HTTPS in production
  2. Set secure cookies with httpOnly and secure flags
  3. Implement rate limiting on auth endpoints
  4. Enable 2FA for sensitive accounts
  5. Regular session rotation for long-lived sessions

Troubleshooting

Common Issues

Session not persisting:

  • Check that BETTER_AUTH_URL matches your domain
  • Verify cookie settings in production

OAuth redirect errors:

  • Ensure callback URLs are configured in provider settings
  • Check that environment variables are set correctly

Email not sending:

  • Verify Resend API key is configured
  • Check email templates for errors