BetterAuth session validation in middleware doesnt work #1025

Closed
opened 2026-03-13 08:19:19 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @CrackedResearcher on GitHub (Apr 12, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

create a middleware.ts file in your nextjs app (app router version 15.3.0-canary.42)

add this code in it
`import { NextRequest, NextResponse } from "next/server";
import { betterFetch } from "@better-fetch/fetch";
import type { AppSession } from "@/types/authTypes";
import { auth } from "./lib/auth";
import { headers } from "next/headers";
import { getSessionCookie } from "better-auth/cookies";

const SUPERUSER_EMAIL = process.env.SUPERUSER_EMAIL;

export async function middleware(request: NextRequest) {

// when this method is used - it works but its painfully very slow - calls the db everytime
// const { data: session } = await betterFetch("/api/auth/get-session", {
// baseURL: request.nextUrl.origin,
// headers: {
// cookie: request.headers.get("cookie") || "",
// },
// });

// this is from better auths documentation - using this right now for testing
const session = getSessionCookie(request, {
cookieName: "session_data",
cookiePrefix: "better-auth"
});

const { pathname } = request.nextUrl;

console.log("---- asll session data is this --->> ", session) // this returns NULL

// no session then
if (!session) {
// tryin to access admin wihout logged in
if (pathname.startsWith("/admin")) {
return NextResponse.redirect(new URL("/auth/admin/login", request.url));
}

// all user routes
if (
  pathname.startsWith("/dashboard") ||
  pathname.startsWith("/withdraw") ||
  pathname.startsWith("/earnings")
) {
  return NextResponse.redirect(new URL("/auth/login", request.url));
}

}

if (pathname.startsWith("/superuser") && pathname !== "/auth/superuser/login") {
if (!session || session.user.email !== SUPERUSER_EMAIL) {
return NextResponse.redirect(new URL("/auth/superuser/login", request.url));
}
}

// user not allowed to access admin route
if (pathname.startsWith("/admin") && session?.user?.role !== "admin") {
return NextResponse.redirect(new URL("/unauthorized/redirect/user", request.url));
}

// same for admins
if (
session?.user?.role === "admin" &&
(pathname.startsWith("/dashboard") ||
pathname.startsWith("/withdraw") ||
pathname.startsWith("/earnings"))
) {
return NextResponse.redirect(new URL("/unauthorized/redirect/admin", request.url));
}

return NextResponse.next();
}

export const config = {
matcher: [
"/admin/:path*",
"/dashboard/:path*",
"/withdraw/:path*",
"/earnings/:path*",
"/superuser/:path*",
// catch-all for other routes except api, static, public files, AND homepage
"/((?!api|_next|favicon.ico|robots.txt|sitemap.xml|static|.\..|^why-us$|^about$|^team$|^testimonials$|^metrics$).*)"
],

};`

Current vs. Expected behavior

as per the documentation you guys have mentioned that using the getSessionCookie would work in middleware but it doesnt - it gives null. so i used a different woraround suggested in the better auths documentation and it was for previous version - it works but the get-session endpoint calls db everytime and it slows down everything. my page load times are painfully very slow

What version of Better Auth are you using?

1.2.5

Provide environment information

OS: MacOS, Windows (both)
Browser: Zen browser (firefox), google chrome

Which area(s) are affected? (Select all that apply)

Client

Auth config (if applicable)

import { db } from "@/lib/db";
import { authSchema } from "./db/schema";
import { betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { customSession } from "better-auth/plugins";
import type { AppSession } from "@/types/authTypes";
import { eq } from "drizzle-orm";
import { sendEmail } from "./email/send-email";
import { getResetPasswordEmailHTML } from "./email/resetPasswordEmail";

export const auth = betterAuth({
  secret: process.env.BETTER_AUTH_SECRET,
  emailAndPassword: {
    enabled: true,
    autoSignIn: false,
    sendResetPassword: async ({ user, url, token }, request) => {
      await sendEmail({
        to: user.email,
        subject: "Reset your password",
        text: getResetPasswordEmailHTML(url),
      });
    },
  },
  session: {
    cookieCache: {
      enabled: true,
      include: [
        "user.id",
        "user.name",
        "user.email",
        "user.emailVerified",
        "user.image",
        "user.createdAt",
        "user.updatedAt",
        "user.role", 
      ],
      maxAge: 10 * 60
    }
  },
  database: drizzleAdapter(db, {
    provider: "pg",
    schema: {
      user: authSchema.users,
      session: authSchema.session,
      account: authSchema.account,
      verification: authSchema.verification
    }
  }),
  socialProviders: {
    "apple": {
      clientId: process.env.APPLE_CLIENT_ID!,
      clientSecret: process.env.APPLE_CLIENT_SECRET!,
    },
    "google": {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }
  },
  plugins: [
    customSession(async ({ user, session }) => {
      console.log("⛏️ customSession executed - fetched from DB - whole user and session data is this ->> \n", user, session);
      const fullUser = await db.query.users.findFirst({
        where: eq(authSchema.users.id, user.id),
      });

      return {
        ...session,
        user: {
          ...user,
          role: fullUser?.role ?? "user",
        },
      } satisfies AppSession;
    }),
  ],
})

Additional context

need a fix for this - if everytime the db gets called to get the session data then it is very slower not only in dev but also for the users

Originally created by @CrackedResearcher on GitHub (Apr 12, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce create a middleware.ts file in your nextjs app (app router version 15.3.0-canary.42) add this code in it `import { NextRequest, NextResponse } from "next/server"; import { betterFetch } from "@better-fetch/fetch"; import type { AppSession } from "@/types/authTypes"; import { auth } from "./lib/auth"; import { headers } from "next/headers"; import { getSessionCookie } from "better-auth/cookies"; const SUPERUSER_EMAIL = process.env.SUPERUSER_EMAIL; export async function middleware(request: NextRequest) { // when this method is used - it works but its painfully very slow - calls the db everytime // const { data: session } = await betterFetch<AppSession>("/api/auth/get-session", { // baseURL: request.nextUrl.origin, // headers: { // cookie: request.headers.get("cookie") || "", // }, // }); // this is from better auths documentation - using this right now for testing const session = getSessionCookie(request, { cookieName: "session_data", cookiePrefix: "better-auth" }); const { pathname } = request.nextUrl; console.log("---- asll session data is this --->> ", session) // this returns NULL // no session then if (!session) { // tryin to access admin wihout logged in if (pathname.startsWith("/admin")) { return NextResponse.redirect(new URL("/auth/admin/login", request.url)); } // all user routes if ( pathname.startsWith("/dashboard") || pathname.startsWith("/withdraw") || pathname.startsWith("/earnings") ) { return NextResponse.redirect(new URL("/auth/login", request.url)); } } if (pathname.startsWith("/superuser") && pathname !== "/auth/superuser/login") { if (!session || session.user.email !== SUPERUSER_EMAIL) { return NextResponse.redirect(new URL("/auth/superuser/login", request.url)); } } // user not allowed to access admin route if (pathname.startsWith("/admin") && session?.user?.role !== "admin") { return NextResponse.redirect(new URL("/unauthorized/redirect/user", request.url)); } // same for admins if ( session?.user?.role === "admin" && (pathname.startsWith("/dashboard") || pathname.startsWith("/withdraw") || pathname.startsWith("/earnings")) ) { return NextResponse.redirect(new URL("/unauthorized/redirect/admin", request.url)); } return NextResponse.next(); } export const config = { matcher: [ "/admin/:path*", "/dashboard/:path*", "/withdraw/:path*", "/earnings/:path*", "/superuser/:path*", // catch-all for other routes except api, static, public files, AND homepage "/((?!api|_next|favicon.ico|robots.txt|sitemap.xml|static|.*\\..*|^why-us$|^about$|^team$|^testimonials$|^metrics$).*)" ], };` ### Current vs. Expected behavior as per the documentation you guys have mentioned that using the getSessionCookie would work in middleware but it doesnt - it gives null. so i used a different woraround suggested in the better auths documentation and it was for previous version - it works but the get-session endpoint calls db everytime and it slows down everything. my page load times are painfully very slow ### What version of Better Auth are you using? 1.2.5 ### Provide environment information ```bash OS: MacOS, Windows (both) Browser: Zen browser (firefox), google chrome ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript import { db } from "@/lib/db"; import { authSchema } from "./db/schema"; import { betterAuth } from "better-auth" import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { customSession } from "better-auth/plugins"; import type { AppSession } from "@/types/authTypes"; import { eq } from "drizzle-orm"; import { sendEmail } from "./email/send-email"; import { getResetPasswordEmailHTML } from "./email/resetPasswordEmail"; export const auth = betterAuth({ secret: process.env.BETTER_AUTH_SECRET, emailAndPassword: { enabled: true, autoSignIn: false, sendResetPassword: async ({ user, url, token }, request) => { await sendEmail({ to: user.email, subject: "Reset your password", text: getResetPasswordEmailHTML(url), }); }, }, session: { cookieCache: { enabled: true, include: [ "user.id", "user.name", "user.email", "user.emailVerified", "user.image", "user.createdAt", "user.updatedAt", "user.role", ], maxAge: 10 * 60 } }, database: drizzleAdapter(db, { provider: "pg", schema: { user: authSchema.users, session: authSchema.session, account: authSchema.account, verification: authSchema.verification } }), socialProviders: { "apple": { clientId: process.env.APPLE_CLIENT_ID!, clientSecret: process.env.APPLE_CLIENT_SECRET!, }, "google": { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, } }, plugins: [ customSession(async ({ user, session }) => { console.log("⛏️ customSession executed - fetched from DB - whole user and session data is this ->> \n", user, session); const fullUser = await db.query.users.findFirst({ where: eq(authSchema.users.id, user.id), }); return { ...session, user: { ...user, role: fullUser?.role ?? "user", }, } satisfies AppSession; }), ], }) ``` ### Additional context need a fix for this - if everytime the db gets called to get the session data then it is very slower not only in dev but also for the users
Author
Owner

@Bekacru commented on GitHub (Apr 12, 2025):

since you didn't change your cookie configuration, remove the config from getSessionCookie as well

//this is wrong 
const session = getSessionCookie(request, {
      cookieName: "session_data",
      cookiePrefix: "better-auth"
});
//do this
const session = getSessionCookie(request);
@Bekacru commented on GitHub (Apr 12, 2025): since you didn't change your cookie configuration, remove the config from getSessionCookie as well ```ts //this is wrong const session = getSessionCookie(request, { cookieName: "session_data", cookiePrefix: "better-auth" }); //do this const session = getSessionCookie(request); ```
Author
Owner

@s3f5 commented on GitHub (Apr 12, 2025):

const sessionCookie = getSessionCookie(request, {
        // Optionally pass config if cookie name or prefix is customized in auth config.
		cookieName: "session_token",
		cookiePrefix: "better-auth"
    });

That one comment 😄

@s3f5 commented on GitHub (Apr 12, 2025): ```ts const sessionCookie = getSessionCookie(request, { // Optionally pass config if cookie name or prefix is customized in auth config. cookieName: "session_token", cookiePrefix: "better-auth" }); ``` That one comment 😄 <p align="left"> <img width="300"src="https://media.tenor.com/y_P9uYv9F4QAAAAM/funny-cant-see.gif"> </p>
Author
Owner

@CrackedResearcher commented on GitHub (Apr 13, 2025):

wdym?

@CrackedResearcher commented on GitHub (Apr 13, 2025): wdym?
Author
Owner

@Kinfe123 commented on GitHub (Apr 14, 2025):

have you tried this

 const session = getSessionCookie(request)

for getting the session from cookiecache

@Kinfe123 commented on GitHub (Apr 14, 2025): have you tried this ```ts const session = getSessionCookie(request) ``` for getting the session from cookiecache
Author
Owner

@CrackedResearcher commented on GitHub (Apr 14, 2025):

yes that worked fine.

On Mon, Apr 14, 2025, 14:06 KinfeMichael Tariku @.***>
wrote:

have you tried this

const session = getSessionCookie(request)

for getting the session from cookiecache


Reply to this email directly, view it on GitHub
https://github.com/better-auth/better-auth/issues/2233#issuecomment-2800886531,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/A4PI54LY5TGWPPN3Z77LENT2ZNXQHAVCNFSM6AAAAAB3AFEK3CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDQMBQHA4DMNJTGE
.
You are receiving this because you authored the thread.Message ID:
@.***>
Kinfe123 left a comment (better-auth/better-auth#2233)
https://github.com/better-auth/better-auth/issues/2233#issuecomment-2800886531

have you tried this

const session = getSessionCookie(request)

for getting the session from cookiecache


Reply to this email directly, view it on GitHub
https://github.com/better-auth/better-auth/issues/2233#issuecomment-2800886531,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/A4PI54LY5TGWPPN3Z77LENT2ZNXQHAVCNFSM6AAAAAB3AFEK3CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDQMBQHA4DMNJTGE
.
You are receiving this because you authored the thread.Message ID:
@.***>

@CrackedResearcher commented on GitHub (Apr 14, 2025): yes that worked fine. On Mon, Apr 14, 2025, 14:06 KinfeMichael Tariku ***@***.***> wrote: > have you tried this > > const session = getSessionCookie(request) > > for getting the session from cookiecache > > — > Reply to this email directly, view it on GitHub > <https://github.com/better-auth/better-auth/issues/2233#issuecomment-2800886531>, > or unsubscribe > <https://github.com/notifications/unsubscribe-auth/A4PI54LY5TGWPPN3Z77LENT2ZNXQHAVCNFSM6AAAAAB3AFEK3CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDQMBQHA4DMNJTGE> > . > You are receiving this because you authored the thread.Message ID: > ***@***.***> > *Kinfe123* left a comment (better-auth/better-auth#2233) > <https://github.com/better-auth/better-auth/issues/2233#issuecomment-2800886531> > > have you tried this > > const session = getSessionCookie(request) > > for getting the session from cookiecache > > — > Reply to this email directly, view it on GitHub > <https://github.com/better-auth/better-auth/issues/2233#issuecomment-2800886531>, > or unsubscribe > <https://github.com/notifications/unsubscribe-auth/A4PI54LY5TGWPPN3Z77LENT2ZNXQHAVCNFSM6AAAAAB3AFEK3CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDQMBQHA4DMNJTGE> > . > You are receiving this because you authored the thread.Message ID: > ***@***.***> >
Author
Owner

@Kinfe123 commented on GitHub (Apr 14, 2025):

so it still calls the db ? or it works fine

@Kinfe123 commented on GitHub (Apr 14, 2025): so it still calls the db ? or it works fine
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1025