Guides
How to Use Supabase Authentication With Next.js
Supabase Auth combined with the App Router requires a specific setup so that session state is available consistently in both server components and client components — this walks through that setup end to end.
Prerequisites
- arrow_rightA Supabase project (free tier is fine)
- arrow_rightA Next.js App Router project
- arrow_right@supabase/supabase-js and @supabase/ssr packages installed
Step 1: Install and Configure
npm install @supabase/supabase-js @supabase/ssrAdd your Supabase project URL and anon key as environment variables (NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY).
Step 2: Create Server and Client Supabase Clients
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: () => cookieStore.getAll() } }
);
}Step 3: Protect Routes With Middleware
Middleware runs before a request reaches a page, making it the right place to check session validity and redirect unauthenticated users before any page code executes — this is faster and more secure than checking auth state inside the page component.
Common Errors
- arrow_rightSession appears logged out on the server but logged in on the client — usually a cookie handling mismatch between the server and client Supabase clients
- arrow_right"Invalid JWT" errors after deploying — confirm environment variables are set correctly in the deployment environment, not just locally
- arrow_rightRedirect loops on protected routes — check the middleware's matcher config isn't also intercepting the login page itself
Security Considerations
- arrow_rightNever expose the Supabase service role key to the client — only the anon key belongs in NEXT_PUBLIC_ variables
- arrow_rightRow-level security policies are the real access control layer — client-side route protection alone isn't sufficient
- arrow_rightValidate the session independently in every API route, not just in middleware
Frequently Asked Questions
Why do I need both a server and client Supabase instance?add
Server components and client components read the session differently — the server client reads from cookies via Next.js's server APIs, while the client instance manages the browser session; using the wrong one in the wrong context causes session mismatches.
Is middleware required for auth to work?add
Not strictly, but without it, unauthenticated users would reach page code before being redirected, which is both slower and a weaker security boundary than checking in middleware first.
How do I handle OAuth providers like Google?add
Configure the provider in the Supabase dashboard, then use supabase.auth.signInWithOAuth() with a redirect URL pointing to a callback route that exchanges the auth code for a session.