Supabase Auth te donne un système d'authentification complet sans écrire un seul serveur : une table auth.users dans Postgres, des JWT signés, et une liaison automatique avec les politiques RLS de ta base. Dans cette leçon, tu vas configurer le client, implémenter le magic link et l'email+mot de passe, récupérer l'utilisateur côté client et côté serveur, puis comprendre comment auth nourrit tes règles de sécurité.
Installer le package SSR
Le SDK de base @supabase/supabase-js gère le client browser. Pour les apps Next.js (App Router ou Pages Router), ajoute aussi @supabase/ssr qui adapte la gestion des cookies pour le rendu serveur :
Créer le client browser
Pour les composants côté client (fichiers avec "use client" ou dans Pages Router), utilise createBrowserClient de @supabase/ssr. Il lit et écrit les tokens dans les cookies du navigateur automatiquement.
Crée un fichier 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_PUBLISHABLE_KEY!
);
}Tu appelleras createClient() dans chaque composant client qui en a besoin. Ne l'instancie pas au niveau module (singleton) dans un contexte SSR : chaque requête doit avoir son propre client pour éviter les fuites de session entre utilisateurs.
Magic link : connexion sans mot de passe
Le magic link est la méthode la plus simple à implémenter. L'utilisateur entre son email, reçoit un lien dans sa boîte, clique dessus, et est connecté. Côté code, c'est une seule fonction :
const supabase = createClient();
const { error } = await supabase.auth.signInWithOtp({
email: "utilisateur@exemple.com",
options: {
emailRedirectTo: "https://ton-app.com/auth/callback",
},
});Le champ emailRedirectTo indique où Supabase doit rediriger l'utilisateur après qu'il a cliqué sur le lien. Supabase attache un code dans l'URL de redirection ; ta route /auth/callback doit l'échanger contre une vraie session.
Route de callback
Crée le fichier app/auth/callback/route.ts :
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const { searchParams, origin } = new URL(request.url);
const code = searchParams.get("code");
if (code) {
const cookieStore = await cookies();
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() { return cookieStore.getAll(); },
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
);
},
},
}
);
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (!error) {
return NextResponse.redirect(`${origin}/dashboard`);
}
}
return NextResponse.redirect(`${origin}/auth/error`);
}Email + mot de passe
Pour les apps qui préfèrent le duo classique email/mot de passe, deux méthodes suffisent :
Créer un compte (signUp) :
const { data, error } = await supabase.auth.signUp({
email: "utilisateur@exemple.com",
password: "mot-de-passe-fort",
options: {
emailRedirectTo: "https://ton-app.com/auth/callback",
},
});Par défaut, Supabase envoie un email de confirmation. L'utilisateur doit cliquer sur le lien avant de pouvoir se connecter. Tu peux désactiver cette confirmation dans Authentication > Providers > Email du dashboard (utile pour le développement local).
Se connecter (signInWithPassword) :
const { data, error } = await supabase.auth.signInWithPassword({
email: "utilisateur@exemple.com",
password: "mot-de-passe-fort",
});Récupérer l'utilisateur connecté
Il existe deux méthodes, et le choix dépend de l'endroit où tu te trouves dans ton code.
Côté client - getSession() :
const { data: { session } } = await supabase.auth.getSession();
console.log(session?.user);getSession() lit directement le cookie local. C'est rapide mais les données ne sont pas revalidées : si le token a été révoqué côté serveur, getSession() peut encore retourner une session valide pendant quelques secondes.
Côté serveur - getUser() :
const { data: { user }, error } = await supabase.auth.getUser();getUser() envoie une requête réseau au serveur Supabase pour valider le JWT. C'est la méthode à utiliser dans les Server Components, les Route Handlers, et le middleware Next.js pour protéger des routes. Ne fais jamais confiance à getSession() dans du code serveur pour prendre des décisions de sécurité.
Se déconnecter :
await supabase.auth.signOut();Lien avec les politiques RLS
Chaque utilisateur authentifié possède un user.id (UUID). Côté Postgres, ce même identifiant est accessible dans les politiques RLS via la fonction auth.uid(). Cela permet d'écrire des règles du type "un utilisateur ne peut lire que ses propres lignes" sans aucune logique applicative supplémentaire.
-- Exemple : un utilisateur ne lit que ses propres todos
create policy "Lecture personnelle"
on public.todos
for select
using ((select auth.uid()) = user_id);La leçon suivante du module, Sécurité avec RLS, couvre la rédaction complète de ces politiques.
Supabase Auth - Next.js SSR guide