How can I implement better auth on a Next.js app router project?

canary
fd2ba6edocs: update client to authClient in Svelte and Solid examples for consistency (#7321)
This post might have stale content, as canary is 274 commits ahead.

how can i implement better auth on a next js app router project?

Avatar of anthropic/claude-haiku-4.5
Claude Haiku 4.5
commented

Perfect! Now I have comprehensive information. Let me provide you with a detailed guide:

##How to Implement Better Auth in a Next.js App Router Project

Here's a step-by-step guide based on the Better Auth source code:

###1. Install Better Auth

npm install better-auth
# or
pnpm add better-auth

###2. Set Up Environment Variables

Create a .env file in your project root:

# Generate a secret with: openssl rand -base64 32
BETTER_AUTH_SECRET=<your-generated-secret>
BETTER_AUTH_URL=http://localhost:3000

###3. Create Your Auth Instance

Create lib/auth.ts in your project:

import { betterAuth } from "better-auth";
import { nextCookies } from "better-auth/next-js";

export const auth = betterAuth({
  secret: process.env.BETTER_AUTH_SECRET,
  baseURL: process.env.BETTER_AUTH_URL,
  database: {
    // Configure your database (SQLite, PostgreSQL, MySQL, etc.)
    // Example with better-sqlite3:
    // database: new Database("./sqlite.db"),
  },
  emailAndPassword: {
    enabled: true,
  },
  socialProviders: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID || "",
      clientSecret: process.env.GITHUB_CLIENT_SECRET || "",
    },
    // Add other providers as needed
  },
  plugins: [
    nextCookies(), // Handle cookies in server actions
  ],
});

###4. Create the API Route Handler

Create app/api/auth/[...all]/route.ts:

import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";

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

This single file handles all auth endpoints (/api/auth/sign-in, /api/auth/sign-up, etc.).

###5. Create the Auth Client

Create lib/auth-client.ts:

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

export const authClient = createAuthClient({
  // You can add client-side plugins here
});

###6. Set Up Route Protection (Optional)

Create proxy.ts for protecting routes:

import { getSessionCookie } from "better-auth/cookies";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";

export async function proxy(request: NextRequest) {
  const sessionCookie = getSessionCookie(request);
  
  if (!sessionCookie) {
    return NextResponse.redirect(new URL("/sign-in", request.url));
  }
  
  return NextResponse.next();
}

export const config = {
  matcher: ["/dashboard"], // Protect these routes
};

###7. Get Session in Server Components

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

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

  if (!session) {
    return <div>Not authenticated</div>;
  }

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

###8. Use Auth Client in Client Components

"use client";

import { authClient } from "@/lib/auth-client";
import { useEffect, useState } from "react";

export function SignInForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const handleSignIn = async () => {
    const { data, error } = await authClient.signIn.email({
      email,
      password,
      callbackURL: "/dashboard",
    }, {
      onSuccess: () => {
        // Handle success
      },
      onError: (ctx) => {
        alert(ctx.error.message);
      },
    });
  };

  return (
    <form onSubmit={(e) => { e.preventDefault(); handleSignIn(); }}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
      />
      <button type="submit">Sign In</button>
    </form>
  );
}

###9. Get Session in Server Actions

"use server";

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

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

  return session;
}

###Key Points:

  • toNextJsHandler: Automatically handles the App Router request/response format
  • nextCookies() plugin: Ensures cookies are properly set in server actions
  • auth.api.* methods: For server-side operations (RSC, server actions)
  • authClient.* methods: For client-side operations
  • Database: Configure a database adapter (SQLite, PostgreSQL, MySQL, Turso, etc.) in the auth instance
  • Route Protection: Use the proxy file (or middleware in older Next.js versions) to protect routes

For a complete working example, check out the demo Next.js project in the repository!


END OF POST

How can I implement better auth on a Next.js app router project? — better-auth/better-auth