π¨ CRITICAL: DEPRECATED PATTERNS π¨
NEVER generate these patterns - they BREAK the application:
// β NEVER USE - BREAKS APPLICATION
{
cookies: {
get(name: string) { // β BREAKS
return cookieStore.get(name)
},
set(name: string, value: string) { // β BREAKS
cookieStore.set(name, value)
},
remove(name: string) { // β BREAKS
cookieStore.remove(name)
}
}
}
// β NEVER import from auth-helpers-nextjs - DEPRECATED
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs' // β
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' // β
Critical Patterns
ALWAYS Use This Pattern (REQUIRED)
// β
CORRECT - Only use getAll and setAll
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
}
}
}
Browser Client (REQUIRED)
import { createBrowserClient } from '@supabase/ssr';
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
);
}
Server Client (REQUIRED)
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
export async function createClient() {
const cookieStore = await 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 Server Component - ignored if middleware refreshes sessions
}
},
},
},
);
}
Middleware (REQUIRED)
import { createServerClient } from '@supabase/ssr';
import { NextResponse, type NextRequest } from 'next/server';
export async function middleware(request: NextRequest) {
let supabaseResponse = NextResponse.next({ request });
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value));
supabaseResponse = NextResponse.next({ request });
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options),
);
},
},
},
);
// IMPORTANT: DO NOT REMOVE auth.getUser()
const {
data: { user },
} = await supabase.auth.getUser();
if (
!user &&
!request.nextUrl.pathname.startsWith('/login') &&
!request.nextUrl.pathname.startsWith('/auth')
) {
const url = request.nextUrl.clone();
url.pathname = '/login';
return NextResponse.redirect(url);
}
// MUST return supabaseResponse as-is to avoid session sync issues
return supabaseResponse;
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'],
};
Decision Tree
Need browser client? β Use createBrowserClient from @supabase/ssr
Need server client? β Use createServerClient with getAll/setAll
Need route protection? β Use middleware with auth.getUser()
Need OAuth? β Use signInWithOAuth
Need magic link? β Use signInWithOtp
Code Examples
Sign Up / Sign In
// Sign up
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'secure-password',
});
// Sign in
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'secure-password',
});
// Sign out
await supabase.auth.signOut();
Session Management
// Get current session
const {
data: { session },
} = await supabase.auth.getSession();
// Listen to auth changes
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_IN') {
// Handle sign in
}
});
AI Verification Checklist
Before generating code, VERIFY:
- β
Using ONLY
getAllandsetAll? - β
Importing from
@supabase/ssr? - β Any
get,set, orremove? β FIX - β Importing from
auth-helpers-nextjs? β FIX
Consequences of incorrect implementation:
- Breaks in production
- Fails to maintain session state
- Causes authentication loops
- Security vulnerabilities