If your Supabase auth sessions disappear on Vercel, the cause is almost always a misconfigured cookie or an incorrect auth callback URL. Fixing it means ensuring your cookie storage uses the same site context across server and client, and that your redirect URLs match your deployed domain exactly. Below is a detailed walkthrough of the cookie callback and config settings that cause this issue.
Why Sessions Vanish: The Cookie and Callback Chain
Supabase Auth issues a session as a JWT (JSON Web Token) and stores it in a cookie. On Vercel, your app runs in two environments: server-side (Node.js or Edge Functions) and client-side (browser). If the cookie is set with a path, domain, or SameSite attribute that doesn’t match between these contexts, the browser may drop it or the server may not see it. The callback URL is the endpoint Supabase redirects to after a user signs in. If that URL doesn’t match your Vercel domain exactly (including trailing slashes or www vs non-www), the session token is never exchanged for a full session, and the user appears logged out.
How Supabase Auth Stores Sessions
When a user signs in, Supabase returns an access token, a refresh token, and a user object. In a typical web app, you store these in a cookie. The default Supabase client library (supabase-js) uses the browser’s localStorage by default, but on Vercel, you often need server-side rendering, which requires cookies. The cookie must be set with the following attributes:
- Name: typically
sb-access-tokenandsb-refresh-token(or a singlesb-auth-token). - Path:
/so it’s sent to all routes. - HttpOnly: recommended for security, but if you need to read it client-side, you’ll need it false.
- SameSite:
Laxis common for most apps;Strictcan break OAuth redirects;Nonerequires Secure. - Secure: must be true in production (HTTPS).
- Domain: omit it or set it to your exact domain (e.g.,
example.comnotwww.example.com).
If any of these attributes are inconsistent between the server and client, the cookie may not be sent with requests, or the session may be lost on page reload.
Common Vercel + Supabase Configuration Pitfalls
Here are the most frequent mistakes that cause sessions to vanish:
- Wrong callback URL in Supabase Dashboard: The redirect URL must be exactly
https://your-app.vercel.app/auth/callback(or your custom domain). If you have a trailing slash or a different path, the OAuth flow fails. - Using
localhostin production: If your callback is set tohttp://localhost:3000, it will only work locally. Vercel preview deployments need their own callback URLs. - Not handling the callback route: You need a route like
/auth/callbackthat exchanges the authorization code for a session. If this route doesn’t exist or doesn’t set the cookie, the session is lost. - Mixing client and server Supabase instances: If you create a Supabase client on the server with a different cookie name than the one used on the client, the session won’t be found.
- Forgetting to refresh the session: Access tokens expire after an hour. If you don’t refresh them using the refresh token, the session vanishes when the token expires.
Step-by-Step: Trace the Cookie and Callback
To diagnose the issue, follow these steps:
- Check your Supabase Dashboard: Go to Authentication → URL Configuration. Ensure the Site URL matches your Vercel domain (e.g.,
https://your-app.vercel.app). Add any redirect URLs you use (likehttps://your-app.vercel.app/auth/callback). - Inspect the callback route: In your Next.js app, find the
/auth/callbackroute. It should callsupabase.auth.exchangeCodeForSession(code)and then store the session in a cookie. If you’re using the@supabase/ssrpackage, it handles this automatically. - Verify cookie settings: In your middleware or server code, create the Supabase client with cookies. For example, in Next.js App Router, you’d use
cookies()fromnext/headers. Ensure the cookie options are consistent: same name, path, and SameSite. - Test with a browser’s dev tools: After signing in, open the Application tab → Cookies. Look for your Supabase cookies. If they’re not there, the callback didn’t set them. If they’re there but disappear on reload, the server isn’t reading them.
- Check server logs: On Vercel, view the function logs for errors like
AuthSessionMissingErrororInvalid JWT. These indicate the cookie isn’t being sent or parsed correctly. - Verify environment variables: Ensure
NEXT_PUBLIC_SUPABASE_URLandNEXT_PUBLIC_SUPABASE_ANON_KEYare set in Vercel’s environment variables, and that they match the values in your local.env.local.
Fixing the Cookie Callback in Next.js (App Router)
If you’re using Next.js App Router, the recommended approach is to use @supabase/ssr to create a server client that reads cookies. Here’s a minimal example:
// lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export function createClient() {
const cookieStore = cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() { return cookieStore.getAll() },
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options))
} catch {
// Called from a Server Component, ignore
}
}
}
}
)
}
And in your callback route:
// app/auth/callback/route.ts
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url)
const code = searchParams.get('code')
if (code) {
const supabase = createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
return NextResponse.redirect(`${origin}/`)
}
}
return NextResponse.redirect(`${origin}/auth/error`)
}
This setup ensures the cookie is set and read consistently. If you’re not using App Router, the principle is the same: read cookies from the request, set cookies on the response.
Alternatives: Client-Only vs. Server-Side Sessions
If you’re still struggling, consider these alternatives:
- Client-only auth: Store the session in localStorage (default supabase-js behavior). This works but doesn’t allow server-side rendering of user-specific data. You’ll need to handle loading states.
- Use a different auth provider: Some developers switch to NextAuth.js (now Auth.js) with Supabase as a database adapter. This handles sessions via JWT in cookies and may be easier to configure.
- Use Vercel’s Edge Middleware: You can refresh the session in middleware to keep it alive. This requires careful cookie handling but can prevent session loss on page navigation.
Frequently Asked Questions
Why does my session work locally but not on Vercel?
Localhost and your Vercel domain are different origins. The callback URL must be added to Supabase’s allowed redirects for each environment. Also, cookies set on localhost (http) may not be secure, while Vercel uses https, so the Secure flag must be set correctly.
What is the correct SameSite attribute for Supabase cookies?
For most apps, Lax is sufficient. It allows the cookie to be sent on top-level navigations (like OAuth redirects) but not on cross-site subrequests. Strict can break OAuth, and None requires Secure and may be blocked by browsers if not set properly.
How do I set up multiple Vercel preview deployments with Supabase?
Each preview deployment has a unique URL like your-app-xyz.vercel.app. You need to add each URL to Supabase’s redirect list, or use a wildcard pattern if Supabase supports it. Alternatively, you can use a single staging environment and disable previews for auth testing.
Why does my session vanish after a page refresh?
This usually means the cookie is not being sent with the server request. Check that the cookie is set with a path of / and that your server client is reading it correctly. Also ensure you’re not setting the cookie only on the client side (e.g., in a useEffect).
Can I use Supabase auth without a callback URL?
Yes, for email/password sign-in, you can use the signInWithPassword method, which returns a session directly without a redirect. However, for OAuth (Google, GitHub, etc.), a callback URL is required to exchange the authorization code.
What if my callback URL is correct but I still get an error?
Check the Vercel function logs for the exact error. Common issues include the code being expired (it lasts only a few minutes), the code being used more than once, or a mismatch between the code verifier and the code challenge (if using PKCE). Ensure your Supabase client uses the same PKCE settings in both the login and callback.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Motorola Phone Recovery: How to Recover Data
- Poco X3 GT Dimensity 1100 67W Fast Charging Launched?5.00 min/km
- Flash Converter: What It Is & How to Use It
- Choosing a Pipe Flow Meter for Swirling Flow
- Convert 2D Videos to Oculus Rift VR: How-To
- DRAM Light on Motherboard: Meaning & Fixes5.00 min/km