Middleware not working?

Hi all, i guess i have a very common use case. but as i am new to better auth maybe you can give me some hints. Stack T3 Stack with better-auth, drizzle, trpc. Usecase: my app is a "backendonly" app which means that only the loginform is shown to the public. next is: my users can have 2 different roles "user" and "admin" any user has to login before he can see something. - /page.tsx => Loginform - /user/page.tsx => Protected Userpage - /admin/page.tsx => Protected Adminpage now the i tried to use a middleware to protect those routes: middleware.ts
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { auth } from '@/lib/auth';

export async function middleware(request: NextRequest) {
console.log("MIDDLEWARE STARTS")
const session = await auth.api.getSession({ headers: request.headers });
console.log(session);
const { pathname } = request.nextUrl;
console.log(pathname);

if (!session) {
// not logged in redirect to /
return NextResponse.redirect(new URL('/', request.url));
}
console.log("ROLLE: ", session.user.role)
if (pathname.startsWith('/admin') && session.user.role !== 'admin') {
return NextResponse.redirect(new URL('/user', request.url));
}

if (pathname.startsWith('/user') && session.user.role !== 'user') {
return NextResponse.redirect(new URL('/admin', request.url));
}
return NextResponse.next();
}

export const config = {
matcher: ['/admin/:path*', '/user/:path*'],
};
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { auth } from '@/lib/auth';

export async function middleware(request: NextRequest) {
console.log("MIDDLEWARE STARTS")
const session = await auth.api.getSession({ headers: request.headers });
console.log(session);
const { pathname } = request.nextUrl;
console.log(pathname);

if (!session) {
// not logged in redirect to /
return NextResponse.redirect(new URL('/', request.url));
}
console.log("ROLLE: ", session.user.role)
if (pathname.startsWith('/admin') && session.user.role !== 'admin') {
return NextResponse.redirect(new URL('/user', request.url));
}

if (pathname.startsWith('/user') && session.user.role !== 'user') {
return NextResponse.redirect(new URL('/admin', request.url));
}
return NextResponse.next();
}

export const config = {
matcher: ['/admin/:path*', '/user/:path*'],
};
but i get this error when im logged in:
ERROR [Better Auth]: INTERNAL_SERVER_ERROR Error: The edge runtime does not support Node.js 'perf_hooks' module.
⨯ [Error [APIError]: Failed to get session]
GET /admin 404
ERROR [Better Auth]: INTERNAL_SERVER_ERROR Error: The edge runtime does not support Node.js 'perf_hooks' module.
⨯ [Error [APIError]: Failed to get session]
GET /admin 404
i already tried as well to add the runtime, but i get another error so im thinking that it is not the preferrable way to protect routes. can you give me some hints how to solve or implement such usecases. is it better to write or use plugins?
Solution:
then i tried to use the code for older nextjs versions ``` const { data: session } = await betterFetch<Session>("/api/auth/get-session", { baseURL: request.nextUrl.origin, headers: {...
Jump to solution
6 Replies
FalconiZzare
FalconiZzare5mo ago
https://www.better-auth.com/docs/integrations/next#middleware Only NextJs 15.2.0 or above support nodejs runtime. Below that you have to just check the existence of the cookie or make an HTTP call to get the full session object in middleware.
Next.js integration | Better Auth
Integrate Better Auth with Next.js.
alpe78
alpe78OP5mo ago
im already on next 15.2.3 but its not gonna work when i add it it shows
Runtime Error
Error: Cannot find the middleware module
DevServer.runMiddleware
node_modules/next/src/server/next-server.ts (1602:15)
async DevServer.runMiddleware
node_modules/next/src/server/dev/next-dev-server.ts (383:22)
async NextNodeServer.handleCatchallMiddlewareRequest
node_modules/next/src/server/next-server.ts (1703:16)
async DevServer.handleRequestImpl
node_modules/next/src/server/base-server.ts (1545:20)
async
node_modules/next/src/server/dev/next-dev-server.ts (512:14)
async Span.traceAsyncFn
node_modules/next/src/trace/trace.ts (143:14)
async DevServer.handleRequest
node_modules/next/src/server/dev/next-dev-server.ts (510:20)
async handleRoute
node_modules/next/src/server/lib/router-utils/resolve-routes.ts (489:17)
async resolveRoutes
node_modules/next/src/server/lib/router-utils/resolve-routes.ts (809:22)
async handleRequest
node_modules/next/src/server/lib/router-server.ts (352:11)
async requestHandlerImpl
node_modules/next/src/server/lib/router-server.ts (590:7)
async Server.requestListener
node_modules/next/src/server/lib/start-server.ts (154:7)
Runtime Error
Error: Cannot find the middleware module
DevServer.runMiddleware
node_modules/next/src/server/next-server.ts (1602:15)
async DevServer.runMiddleware
node_modules/next/src/server/dev/next-dev-server.ts (383:22)
async NextNodeServer.handleCatchallMiddlewareRequest
node_modules/next/src/server/next-server.ts (1703:16)
async DevServer.handleRequestImpl
node_modules/next/src/server/base-server.ts (1545:20)
async
node_modules/next/src/server/dev/next-dev-server.ts (512:14)
async Span.traceAsyncFn
node_modules/next/src/trace/trace.ts (143:14)
async DevServer.handleRequest
node_modules/next/src/server/dev/next-dev-server.ts (510:20)
async handleRoute
node_modules/next/src/server/lib/router-utils/resolve-routes.ts (489:17)
async resolveRoutes
node_modules/next/src/server/lib/router-utils/resolve-routes.ts (809:22)
async handleRequest
node_modules/next/src/server/lib/router-server.ts (352:11)
async requestHandlerImpl
node_modules/next/src/server/lib/router-server.ts (590:7)
async Server.requestListener
node_modules/next/src/server/lib/start-server.ts (154:7)
FalconiZzare
FalconiZzare5mo ago
I haven't tried this yet on Nextjs15.2.xx. But I would suggest you to write the middleware as per the better auth doc and just check for existence of the session. Then in the beginning of each protected route do the check again by calling API. that would be the best both security and peformance wise.
alpe78
alpe78OP5mo ago
i upgraded to next 15.3.2 and used the code for nextjs 15.2.0 and above. it still does not work.
Solution
alpe78
alpe785mo ago
then i tried to use the code for older nextjs versions
const { data: session } = await betterFetch<Session>("/api/auth/get-session", {
baseURL: request.nextUrl.origin,
headers: {
cookie: request.headers.get("cookie") || "", // Forward the cookies from the request
},
});
const { data: session } = await betterFetch<Session>("/api/auth/get-session", {
baseURL: request.nextUrl.origin,
headers: {
cookie: request.headers.get("cookie") || "", // Forward the cookies from the request
},
});
this works perfectly
Rahif
Rahif4mo ago
The problem here is that the middleware approach provided by better-auth only works if you have the middleware runtime using Node.js. And nodejs middleware runtime is experimental on Next.js 15, you have to enable it on config, read this: https://nextjs.org/docs/app/building-your-application/routing/middleware#runtime. Also Next.js requires canary build to turn on this experimental feature, otherwise it will throw the below error:
The experimental feature "experimental.nodeMiddleware" can only be enabled when using the latest canary version of Next.js.
Two solutions: 1. Use the canary build Next.js along with experimental Node.js runtime middleware turned on. 2. Use the old way as you provided: https://www.better-auth.com/docs/integrations/next#for-nextjs-release-1517-and-below

Did you find this page helpful?