Better auth does not work on NextJS

Hi guys, im trying to add Better Auth to my empty nextjs project but it does not work. I copied the demo project and it does work there, i copied every auth related file but i still cant get it to work in my project. im trying to check the session on a server component like this but the session is always null. I have not added a database as i dont need one, im logging in using my google account. I keep getting redirected to /sign-in and the console shows this error:
2025-04-20T19:46:49.619Z WARN [Better Auth]: No database configuration provided. Using memory adapter in development
[Error [APIError]: ] {
status: 'UNAUTHORIZED',
body: undefined,
headers: {},
statusCode: 401
}
GET /dashboard 307 in 67ms
GET /sign-in 200 in 65ms
2025-04-20T19:46:49.619Z WARN [Better Auth]: No database configuration provided. Using memory adapter in development
[Error [APIError]: ] {
status: 'UNAUTHORIZED',
body: undefined,
headers: {},
statusCode: 401
}
GET /dashboard 307 in 67ms
GET /sign-in 200 in 65ms
My dashboard page:
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";

export default async function DashboardPage() {
const [session, activeSessions] = await Promise.all([
auth.api.getSession({
headers: await headers(),
}),
auth.api.listSessions({
headers: await headers(),
}),
]).catch((e) => {
console.log(e);
throw redirect("/sign-in");
});

console.log(activeSessions, session);
return (
<div className="w-full">
<div className="flex gap-4 flex-col">
<h1 className="text-2xl font-bold">{session?.user}</h1>
</div>
</div>
);
}

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

export default async function DashboardPage() {
const [session, activeSessions] = await Promise.all([
auth.api.getSession({
headers: await headers(),
}),
auth.api.listSessions({
headers: await headers(),
}),
]).catch((e) => {
console.log(e);
throw redirect("/sign-in");
});

console.log(activeSessions, session);
return (
<div className="w-full">
<div className="flex gap-4 flex-col">
<h1 className="text-2xl font-bold">{session?.user}</h1>
</div>
</div>
);
}

14 Replies
daveycodez
daveycodez2w ago
Did you enable the nextCookies plugin
jeffreyyvdb
jeffreyyvdbOP2w ago
@daveycodez Yes, i added it like this but does not seem to help
import { betterAuth } from "better-auth";
import { nextCookies } from "better-auth/next-js";

export const auth = betterAuth({
appName: "Better Auth Demo",
socialProviders: {
google: {
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || "",
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
},
},
plugins: [nextCookies()],
});
import { betterAuth } from "better-auth";
import { nextCookies } from "better-auth/next-js";

export const auth = betterAuth({
appName: "Better Auth Demo",
socialProviders: {
google: {
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || "",
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
},
},
plugins: [nextCookies()],
});
daveycodez
daveycodez2w ago
Are you seeing cookies get set in chrome inspector
rhitune
rhitune2w ago
2025-04-20T19:46:49.619Z WARN [Better Auth]: No database configuration provided. Using memory adapter in development is it your full auth config? if its , its wrong if not, send all config not about nextCookies plugin
jeffreyyvdb
jeffreyyvdbOP2w ago
Yes this is my auth config, i also have a auth-client, middleware and a api route for auth. auth.ts:
typescript
import { betterAuth } from "better-auth";
import { nextCookies } from "better-auth/next-js";

export const auth = betterAuth({
appName: "Better Auth Demo",
socialProviders: {
google: {
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || "",
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
},
},
plugins: [nextCookies()],
});
typescript
import { betterAuth } from "better-auth";
import { nextCookies } from "better-auth/next-js";

export const auth = betterAuth({
appName: "Better Auth Demo",
socialProviders: {
google: {
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || "",
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
},
},
plugins: [nextCookies()],
});
auth-client.ts:
typescript
import { createAuthClient } from "better-auth/react";

import { toast } from "sonner";

export const client = createAuthClient({
fetchOptions: {
onError(e) {
if (e.error.status === 429) {
toast.error("Too many requests. Please try again later.");
}
},
},
});

export const { signUp, signIn, signOut, useSession } = client;

client.$store.listen("$sessionSignal", async () => {});
typescript
import { createAuthClient } from "better-auth/react";

import { toast } from "sonner";

export const client = createAuthClient({
fetchOptions: {
onError(e) {
if (e.error.status === 429) {
toast.error("Too many requests. Please try again later.");
}
},
},
});

export const { signUp, signIn, signOut, useSession } = client;

client.$store.listen("$sessionSignal", async () => {});
Middleware
typescript
import { NextRequest, NextResponse } from "next/server";
import { getSessionCookie } from "better-auth/cookies";

export async function middleware(request: NextRequest) {
const cookies = getSessionCookie(request);

if (!cookies) {
return NextResponse.redirect(new URL("/", request.url));
}
return NextResponse.next();
}

export const config = {
matcher: ["/"],
};
typescript
import { NextRequest, NextResponse } from "next/server";
import { getSessionCookie } from "better-auth/cookies";

export async function middleware(request: NextRequest) {
const cookies = getSessionCookie(request);

if (!cookies) {
return NextResponse.redirect(new URL("/", request.url));
}
return NextResponse.next();
}

export const config = {
matcher: ["/"],
};
api/auth/[...all]/route.ts:
typescript
import { auth } from "@/lib/auth"; // path to your auth file
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth);
typescript
import { auth } from "@/lib/auth"; // path to your auth file
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth);
Do i miss anything?
daveycodez
daveycodez2w ago
Your middleware looks like an infinite redirect whenever at "/" and no cookies, redirect to "/"
jeffreyyvdb
jeffreyyvdbOP2w ago
true, i changed it to be more logical, but the issues still exists
import { NextRequest, NextResponse } from "next/server";
import { getSessionCookie } from "better-auth/cookies";

export async function middleware(request: NextRequest) {
const cookies = getSessionCookie(request);

if (!cookies) {
return NextResponse.redirect(new URL("/sign-in", request.url));
}
return NextResponse.next();
}

export const config = {
matcher: ["/dashboard"],
};
import { NextRequest, NextResponse } from "next/server";
import { getSessionCookie } from "better-auth/cookies";

export async function middleware(request: NextRequest) {
const cookies = getSessionCookie(request);

if (!cookies) {
return NextResponse.redirect(new URL("/sign-in", request.url));
}
return NextResponse.next();
}

export const config = {
matcher: ["/dashboard"],
};
daveycodez
daveycodez2w ago
Cookies in Chrome console?
jeffreyyvdb
jeffreyyvdbOP2w ago
Seems to be okay
No description
MKTSoft
MKTSoft7d ago
For better performance, you can change your middleware to see. 
import { NextRequest, NextResponse } from "next/server";
import { getSessionCookie } from "better-auth/cookies";

export async function middleware(request: NextRequest) {
// add here all your public paths
const path = request.nextUrl.pathname;
const publicPaths = ["/", "/sign-in", "/sign-up", "/forgot-password"];
// and here your api path
const apiPaths = "/api";

const cookies = getSessionCookie(request);

// Ignore your API path
if (path.startsWith(apiPaths)) {
return NextResponse.next();
}

if (!cookies && !publicPaths.includes(path)) {
return NextResponse.redirect(new URL("/sign-in", request.url));
}
return NextResponse.next();
}

// Change your config like this
export const config = {
// Skip Next.js internals and all static files, unless found in search params
"/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)",
// Always run for API routes
"/(api|trpc)(.*)",
};
import { NextRequest, NextResponse } from "next/server";
import { getSessionCookie } from "better-auth/cookies";

export async function middleware(request: NextRequest) {
// add here all your public paths
const path = request.nextUrl.pathname;
const publicPaths = ["/", "/sign-in", "/sign-up", "/forgot-password"];
// and here your api path
const apiPaths = "/api";

const cookies = getSessionCookie(request);

// Ignore your API path
if (path.startsWith(apiPaths)) {
return NextResponse.next();
}

if (!cookies && !publicPaths.includes(path)) {
return NextResponse.redirect(new URL("/sign-in", request.url));
}
return NextResponse.next();
}

// Change your config like this
export const config = {
// Skip Next.js internals and all static files, unless found in search params
"/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)",
// Always run for API routes
"/(api|trpc)(.*)",
};
jeffreyyvdb
jeffreyyvdbOP7d ago
Okay thank you, but does not seem to be the solution to why I don't have a session in my dashboard page (server side)
rhitune
rhitune7d ago
bro where is your database
database: drizzleAdapter(db, {
provider: "pg",
}),
database: drizzleAdapter(db, {
provider: "pg",
}),
of course you cant access to session because there is no database
jeffreyyvdb
jeffreyyvdbOP7d ago
2025-04-20T19:46:49.619Z WARN [Better Auth]: No database configuration provided. Using memory adapter in development This warning made me think it is possible to work with the in memory adapter
daveycodez
daveycodez7d ago
Don’t do this if you host on Vercel. This will be excessive middleware requests. It’s better to only run it when you need it The only time you need catch all middleware is for localization routing (next-intl) If you are only protecting specific routes with optimistic cookie checks, then hardcode them into the middleware check Next.js docs encourage you to use practices that cause you to pay $$$$ to Vercel unnecessarily across the board Like excessive dynamic SSR

Did you find this page helpful?