Why Better Auth
Better Auth is a fresh take on auth for TypeScript apps. It's unopinionated about your database, supports multiple providers out of the box, and doesn't lock you into a hosted service. If you want to own your auth layer, this is a great starting point.
Install
npm install better-auth
Server Config
Create src/lib/auth.ts. This is where you wire Better Auth to your database and enable providers.
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { nextCookies } from "better-auth/next-js";
import { prisma } from "./prisma";
export const auth = betterAuth({
database: prismaAdapter(prisma, { provider: "postgresql" }),
emailAndPassword: {
enabled: true,
},
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
},
},
plugins: [nextCookies()],
});
Database Schema
Better Auth stores sessions in your database — not JWTs. Add the required models to your Prisma schema:
model User {
id String @id @default(cuid())
name String
email String @unique
emailVerified Boolean @default(false)
sessions Session[]
accounts Account[]
}
model Session {
id String @id @default(cuid())
token String @unique
expiresAt DateTime
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model Account {
id String @id @default(cuid())
userId String
providerId String
accountId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
Run npx prisma migrate dev to apply them.
API Route
Mount Better Auth's handler at /api/auth/[...all]/route.ts:
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
export const { GET, POST } = toNextJsHandler(auth);
Client Helper
Create a client for your components:
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient();
export const { signIn, signUp, signOut, useSession } = authClient;
Using It
"use client";
import { useSession, signIn, signOut } from "@/lib/auth-client";
export function UserMenu() {
const { data: session } = useSession();
if (!session?.user) {
return <button onClick={() => signIn.email({ email, password })}>Sign in</button>;
}
return (
<div>
<span>{session.user.name}</span>
<button onClick={() => signOut()}>Sign out</button>
</div>
);
}
Server-Side Session
For Server Components or Server Actions, create a helper:
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
export async function getServerSession() {
return await auth.api.getSession({ headers: await headers() });
}
export async function requireSession() {
const session = await getServerSession();
if (!session?.user) throw new Error("Unauthorized");
return session;
}
That's it. You now have email/password, Google OAuth, and database-backed sessions.