All articles

May 15, 2026

Setting up authentication in Next.js with Better Auth

Better Auth is the authentication library that should have existed years ago. Here is how to set it up in a Next.js app with email/password, Google OAuth, and password reset.

Authentication is one of those things every SaaS product needs but nobody wants to build from scratch. The options have historically been: use a hosted service (Auth0, Clerk) and pay per user, or roll your own and spend a week on password reset flows.

Better Auth is a third option: an open-source auth library that runs in your own infrastructure, handles all the common flows, and does not charge per monthly active user.

What Better Auth gives you out of the box

  • Email and password authentication with proper hashing (argon2)
  • Password reset via email
  • Email verification (optional)
  • OAuth providers (Google, GitHub, and others)
  • Session management with refresh tokens
  • TypeScript types throughout

It stores everything in your database using your ORM. With Drizzle and Cloudflare D1, sessions live in your D1 database and the full auth flow runs at the Cloudflare edge.

Basic setup

Install the package:

npm install better-auth

Create the auth configuration. This is where you define your database adapter, session settings, and providers:

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/server/db";

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "sqlite" }),
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: false,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
  },
  session: {
    expiresIn: 60 * 60 * 24 * 30, // 30 days
    updateAge: 60 * 60 * 24,       // refresh if older than 1 day
  },
});

Create the catch-all API route that handles all auth requests:

// src/app/api/auth/[...all]/route.ts
import { auth } from "@/server/auth";
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth);

The client setup

Better Auth provides a typed client that matches your server configuration:

import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
  baseURL: process.env.NEXT_PUBLIC_APP_URL,
});

Use it in your components:

const { data: session } = authClient.useSession();
const { signIn, signOut } = authClient;

Google OAuth in five minutes

  1. Go to console.cloud.google.com
  2. Create a new project (or use an existing one)
  3. Enable the Google OAuth2 API
  4. Create OAuth 2.0 credentials (Web application type)
  5. Add your callback URL: https://yourdomain.com/api/auth/callback/google
  6. Copy the Client ID and Client Secret into your environment variables

For local development, add http://localhost:3000/api/auth/callback/google as an authorized redirect URI.

Password reset flow

Better Auth handles the full password reset flow. You just need to configure the email sender:

export const auth = betterAuth({
  // ...
  emailAndPassword: {
    enabled: true,
    sendResetPassword: async ({ user, url }) => {
      await sendEmail({
        to: user.email,
        subject: "Reset your password",
        react: PasswordResetEmail({ resetUrl: url }),
      });
    },
  },
});

The URL is a signed, time-limited link that Better Auth generates and validates automatically.

Getting the current user in a Server Component

import { auth } from "@/server/auth";
import { headers } from "next/headers";

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

  if (!session) redirect("/login");

  return <div>Hello, {session.user.name}</div>;
}

This is the pattern used throughout Flint — server-side session checks with automatic redirect for unauthenticated users.