Learn

Authentification email et magic link

Supabase

Le module auth Supabase en pratique : signup, login, session côté client.

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 :

shell
pnpm add @supabase/supabase-js @supabase/ssr

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 :

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.

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 :

ts
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 :

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) :

ts
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) :

ts
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() :

ts
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() :

ts
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 :

ts
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.

sql
-- 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

Sources

À côté

À côté · supabaseBase de données et Row Level Security
À côté · fullstackAuthentification et sessions

Coche les étapes pour débloquer la suite

Retour au cours