Next.js Middleware Session Validation#
Better Auth supports multiple middleware strategies for session-based route protection in Next.js, with the correct approach depending on the Next.js version and the trade-off between performance and security.
Core principle: Middleware-level checks should be treated as optimistic redirects only. Always re-validate the session in the server component, server action, or route handler that handles sensitive data or state changes.
Approach by Next.js Version#
Next.js 16+ — Proxy Mode#
Next.js 16 replaces middleware.ts with proxy.ts. The function signature changes from middleware → proxy, but all Better Auth methods work identically.
The proxy runs on the Node.js runtime, enabling full session validation via auth.api.getSession() with database access — no HTTP round-trip required.
Migration: Use the Next.js codemod (npx @next/codemod@canary middleware-to-proxy .) or manually rename the file and function.
Next.js 15.2.0+ — Node.js Runtime Middleware#
Next.js 15.2.0 introduced experimental Node.js runtime support for middleware. Set runtime: "nodejs" in the exported config object to unlock auth.api.getSession() with full database access.
Note: Node.js runtime in middleware is experimental before Next.js 16. Upgrading to Next.js 16+ is recommended for stable proxy support.
Next.js 13–15.1.x — Edge Runtime Middleware#
Edge Runtime cannot make database calls. Two strategies are available:
getSessionCookie(request)— synchronously reads the session token from request cookies. Checks cookie existence only; does not validate or decode the session. Suitable for optimistic redirects.getCookieCache(request)— async function that decodes the session from a signed/encrypted cookie cache (supportscompact,jwt,jweencoding strategies). Validates signature and expiry, but no database check.- HTTP fetch to
/api/auth/get-session— for 15.1.x and below, the only way to get a full validated session is via an HTTP call back to the auth route, forwarding request cookies.
Cookie-Based Check Functions#
Both helpers are exported from better-auth/cookies and located in packages/better-auth/src/cookies/index.ts.
| Function | Validates? | DB Access | Runtime |
|---|---|---|---|
getSessionCookie(req) | ❌ Existence only | ❌ | Edge + Node |
getCookieCache(req) | ✅ Signature/expiry | ❌ | Edge + Node |
auth.api.getSession(…) | ✅ Full DB lookup | ✅ | Node only |
Custom cookie names: If you've configured a custom cookieName or cookiePrefix in auth.ts, pass matching options to getSessionCookie() — it does not automatically read from auth.ts.
Server-Side Session Validation (Required for Security)#
Middleware redirects are never sufficient on their own. Validate the session in every protected page or action using auth.api.getSession():
// app/dashboard/page.tsx
const session = await auth.api.getSession({ headers: await headers() });
if (!session) redirect("/sign-in");
In RSCs, the cookie cache is not refreshed because RSCs cannot set cookies — it only updates through client-initiated server actions or route handlers.
Session Validation Internals#
The central session resolution function is getSessionFromCtx, which decides between cookie cache and database lookup based on deployment mode (stateful vs. stateless).
In stateful deployments (database or secondaryStorage configured), token routes force disableCookieCache: true so that server-side session revocations take immediate effect. This is gated by hasServerSessionStore().
Known issue (v1.6.x): A concurrency race in ensureAsyncStorage can cause intermittent "No request state found" errors and spurious null session returns on cold isolate startup, most commonly on edge runtimes fanning out parallel auth.api.getSession() calls. Workaround: serialize the first call on cold start. Fix tracked in PR #9862.
Key References#
| Resource | Link |
|---|---|
| Next.js integration docs | better-auth.com/docs/integrations/next |
getSessionCookie / getCookieCache source | packages/better-auth/src/cookies/index.ts |
getSessionFromCtx source | packages/better-auth/src/api/routes/session.ts |
toNextJsHandler source | packages/better-auth/src/integrations/next-js.ts |
| Session Management internals KB |