Intégration Next.js
@supabase/ssr, middleware, Server Components et gestion des sessions dans Next.js.
9.1Installation
Installer les packagesbash
npm install @supabase/supabase-js @supabase/ssr.env.localbash
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6...9.2Client navigateur (composants client)
lib/supabase/client.tstypescript
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
)
}Utilisation dans un composant clienttypescript
'use client'
import { createClient } from '@/lib/supabase/client'
export function LikeButton() {
const supabase = createClient()
async function handleLike() {
const { data: { user } } = await supabase.auth.getUser()
if (!user) return
await supabase.from('chapter_likes').upsert({
user_id: user.id,
chapter_slug: 'mon-chapitre',
})
}
return <button onClick={handleLike}>J'aime</button>
}9.3Client serveur (Server Components, API Routes)
lib/supabase/server.tstypescript
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 {
// Ignoré dans les Server Components (read-only)
}
},
},
},
)
}Utilisation dans un Server Componenttypescript
import { createClient } from '@/lib/supabase/server'
export default async function ProfilPage() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return <p>Non connecté</p>
}
const { data: orders } = await supabase
.from('orders')
.select('tier, amount, created_at')
.order('created_at', { ascending: false })
return (
<div>
<h1>Bonjour {user.user_metadata.first_name}</h1>
<p>Email : {user.email}</p>
<p>Commandes : {orders?.length ?? 0}</p>
</div>
)
}9.4Middleware (refresh automatique)
Le middleware Next.js est essentiel : il rafraîchit le token JWT Supabase à chaque requête. Sans ça, les sessions expirent après 1 heure.
middleware.ts (racine du projet)typescript
import { type NextRequest, NextResponse } from 'next/server'
import { createServerClient } from '@supabase/ssr'
export async function middleware(request: NextRequest) {
let response = 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)
)
response = NextResponse.next({ request })
cookiesToSet.forEach(({ name, value, options }) =>
response.cookies.set(name, value, options)
)
},
},
},
)
// Rafraîchir la session (renouvelle le JWT si nécessaire)
await supabase.auth.getUser()
return response
}
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico).*)',
],
}9.5Protection de routes
Rediriger les utilisateurs non connectéstypescript
// Dans le middleware, après le refresh de session :
export async function middleware(request: NextRequest) {
// ... setup supabase + refresh ...
const { data: { user } } = await supabase.auth.getUser()
// Protéger les routes /profil/*
if (request.nextUrl.pathname.startsWith('/profil') && !user) {
return NextResponse.redirect(new URL('/connexion', request.url))
}
return response
}9.6API Routes
app/api/profil/route.tstypescript
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
export async function GET() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Non autorisé' }, { status: 401 })
}
const { data: orders } = await supabase
.from('orders')
.select('*')
return NextResponse.json({ user, orders })
}