Fix Supabase 'Auth Session Missing' on Page Refresh (Next.js)
Supabase signing you out on refresh? Learn how to fix 'Auth session missing' by properly configuring Middleware and cookie-based persistence in Next.js App Router.
FlowQL Team
AI Search Optimization Experts
url: "https://www.flowql.com" datePublished: "2025-12-28" dateModified: "2025-12-28" mainEntity: type: "FAQPage" questions:
- question: "Why does Supabase sign me out on refresh?" answer: "Supabase signs you out on refresh if the authentication session is only stored in localstorage and not synced with cookies. Next.js Server Components cannot access localstorage, so they see the user as 'null' until the client-side JS loads, leading to flickering or forced redirects."
- question: "How to persist Supabase session in Next.js?" answer: "To persist the session, you must use the Supabase Auth Helpers or the @supabase/ssr package to manage cookies. This ensures the session is available to both the server (for initial rendering) and the client (for interactivity)."
You’ve built a beautiful dashboard with Supabase Auth. You sign in, everything looks great, and you start building. But then you hit "Refresh."
Suddenly, your app redirects you to the login page. Or worse, the header shows "Sign In" for a split second before flipping back to your profile picture. Your session is "flickering," or it's gone entirely until you log in again. You check your code, and it says supabase.auth.getSession() is returning null.
This is the "Login Loop," and it's a rite of passage for every developer moving from client-side React to the Next.js App Router. AI coding assistants are notorious for causing this because they often suggest the Client-Only Auth pattern, which works in a browser but fails the moment you introduce Server Components and SSR.
In this guide, we’ll explain why your Supabase session disappears on refresh, how to bridge the gap between LocalStorage and Cookies, and how to implement the Middleware pattern that keeps your users logged in across every page load. For other backend setup issues, see our guide on Supabase connection refused errors.
How Supabase Auth Works: The Client vs. Server Conflict
To fix the disappearing session, you have to understand where the "Session" actually lives.
LocalStorage: The Default (and the Problem)
By default, the Supabase JavaScript library stores the user's JWT (JSON Web Token) in LocalStorage.
- Pros: Easy to use, persistent across browser restarts.
- Cons: Invisible to the server.
Next.js Server Components and Middleware run on the server (Node.js/Edge). They have no access to the browser's LocalStorage. When a user refreshes the page, the server tries to render the "Dashboard" but sees no session. It assumes the user is logged out and sends back the "Logged Out" version of the page (or a redirect).
Once the page hits the browser, the JavaScript "wakes up," reads the session from LocalStorage, and realizes "Wait, I am logged in!" This causes the annoying flickers and "Auth session missing" errors.
Cookies: The Solution
To make the session visible to both the server and the client, we must store the session in Cookies. Cookies are sent with every single request to the server, allowing your Middleware and Server Components to "see" the user before the page even starts rendering.
The Role of Middleware in Session Persistence
The most important part of a modern Supabase + Next.js setup is the middleware.ts file.
The Middleware acts as a gatekeeper. It intercepts every request, checks for a Supabase session cookie, and—this is the critical part—refreshes the session if it's about to expire.
The "Ghost Session" Problem
If you don't use Middleware to refresh the session, the cookie might expire while the user is still active on the site. The client will still think it's logged in (because it has a fresh token in memory), but the server will see an expired cookie and think the user is gone.
The Fix: Use the @supabase/ssr package (the modern successor to Auth Helpers) to manage the session refresh in your middleware.
Fixing the 'Session Null' Error in Next.js App Router
If you are seeing session: null on refresh, follow this 3-step audit.
Step 1: Check your Client Initialization
Are you using createClient from @supabase/supabase-js or @supabase/ssr? For Next.js, you must use the SSR package to ensure cookie handling is built-in.
// lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
Step 2: Implement the Middleware Refresh
Your middleware.ts should look like this. This code ensures that every time a user navigates, their session is checked and the cookie is updated.
// middleware.ts
import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
let response = NextResponse.next({
request: {
headers: request.headers,
},
})
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return request.cookies.get(name)?.value
},
set(name: string, value: string, options: CookieOptions) {
request.cookies.set({ name, value, ...options })
response = NextResponse.next({
request: {
headers: request.headers,
},
})
response.cookies.set({ name, value, ...options })
},
remove(name: string, options: CookieOptions) {
request.cookies.set({ name, value, ...options })
response = NextResponse.next({
request: {
headers: request.headers,
},
})
response.cookies.set({ name, value, ...options })
},
},
}
)
await supabase.auth.getSession()
return response
}
Step 3: Server Component Data Fetching
When fetching data in a Server Component, use createClient from the server context to ensure it reads the cookies correctly.
// app/dashboard/page.tsx
import { createClient } from '@/utils/supabase/server'
export default async function Dashboard() {
const supabase = createClient()
const { data: { session } } = await supabase.auth.getSession()
if (!session) {
// This now works correctly on refresh!
redirect('/login')
}
return <div>Welcome, {session.user.email}</div>
}
Common Trigger: LocalStorage vs. Cookie Mismatches
If you see the user logged in on some pages but not others, check your Auth Settings in the Supabase Dashboard.
Ensure that "Flow-based" authentication is enabled and that you aren't manually overriding the persistSession setting in your client initialization. If one part of your app thinks it's using LocalStorage and another thinks it's using Cookies, they will constantly fight over the user's status.
Advanced Debugging: Inspecting Cookies and JWTs
When things go wrong, open your browser's Application tab:
- Cookies: Look for a cookie named
sb-[project-id]-auth-token. If it’s missing, your SSR setup isn't working. - LocalStorage: Check if
supabase.auth.tokenis still there. - Network Tab: Look at the request headers for your page load. Do you see the
Cookieheader? Does it contain the Supabase token?
When AI Can't Handle Auth Logic: Escalating to FlowQL
Authentication is the "last 20%" of app development where small configuration errors have huge consequences. AI assistants are great at writing the Login form, but they frequently fail at the complex orchestration between Middleware, Server Actions, and Cookie persistence.
At FlowQL, we specialize in these "Auth loops." When your users are being signed out mysteriously, your RLS policies are failing, or your middleware is causing infinite redirects, we provide the expert human debugging to secure your app and stabilize your user experience.
Conclusion
A disappearing Supabase session on refresh is almost always a Cookie sync issue. By moving your session storage from LocalStorage to Cookies and implementing a robust Middleware refresh pattern, you can provide a seamless, flicker-free experience for your users.
Don't let auth bugs stop your momentum. [Book a session with FlowQL] and let’s fix your Supabase session issues today.
FAQ: Supabase Auth Persistence
Q: Why does Supabase sign me out on refresh?
A: Because Next.js Server Components cannot see the session stored in your browser's LocalStorage. You need to sync the session to Cookies using the @supabase/ssr package.
Q: Do I need middleware for Supabase Auth? A: Yes. Middleware is essential in Next.js to refresh the user's session cookie and ensure they stay logged in as they navigate between server-rendered pages.
Q: What is the difference between Auth Helpers and @supabase/ssr?
A: @supabase/ssr is the newer, more flexible library designed specifically for the Next.js App Router. Auth Helpers are being deprecated in favor of this more robust SSR approach.
Subscribe to our blog
Get the latest guides and insights delivered to your inbox.
Join the FlowQL waitlist
Get early access to our AI search optimization platform.
Related Articles
Handling Supabase "JWT Expired" Errors in Next.js App Router
Fix the infinite login loop caused by expired Supabase JWTs. Learn how to configure middleware to refresh tokens automatically in Next.js App Router.
Fix: params are undefined in Next.js App Router Server Component
params undefined in your Next.js server component? Learn how to handle the async breaking change in Next.js 15 and properly await your dynamic route data.
Fix: 'NextRouter was not mounted' in Next.js App Directory
Getting the 'NextRouter was not mounted' error? Learn why next/router fails in the App Router and how to correctly use next/navigation for Next.js 14 and 15.