Guide · SaaS & dev

Authentification Supabase pour Next.js

Quickstart Next.js officiel, mot de passe et session par cookie. Ne mélangez pas les chemins de fichiers des guides Supabase. Non rejoué le 2026-10-18.

Supabase Auth distingue l’authentification, vérifier qui est la personne, de l’autorisation, vérifier ce qu’elle peut lire. La page Auth relue le 2026-10-18 dit que l’authentification passe par des JWT, et que l’autorisation sur les lignes passe par les politiques RLS quand le jeton accompagne la requête.

Pour une app Next.js, deux guides officiels coexistent. Le quickstart crée un projet depuis le modèle with-supabase. Le guide SSR vous fait copier des utilitaires dans lib/supabase. Le guide mot de passe, flux PKCE, importe encore un client depuis @/utils/supabase/server. Ces chemins ne sont pas interchangeables. Cette page suit le quickstart, puis les règles qui restent vraies quel que soit le dossier. Les commandes n’ont pas été rejouées le 2026-10-18. Aucun compte n’a été créé, aucune capture n’est montrée.

Quickstart Next.js, dans l’ordre de la page

Source : Use Supabase Auth with Next.js, relue le 2026-10-18.

1. Créer le projet

La page envoie vers database.new. Elle dit que la base a déjà une table d’utilisateurs, vide au départ. La requête indiquée dans l’éditeur SQL est :

select * from auth.users;

Résultat attendu, d’après la page : la table existe et ne contient pas encore les utilisateurs de votre app. Nous n’avons pas ouvert de projet, donc nous ne publions pas de nombre de lignes.

2. Créer l’app

Le modèle apporte l’auth par cookie, TypeScript et Tailwind, d’après le quickstart. La commande écrite est :

npx create-next-app -e with-supabase

Résultat attendu : un dossier d’app. La page ne liste pas les fichiers générés dans l’extrait relu. Ne les inventez pas. Ouvrez le dépôt créé et lisez ses imports avant d’en coller d’autres depuis un second guide.

Erreur fréquente : lancer cette commande dans un app déjà en production pour « ajouter Supabase ». Le quickstart crée une app neuve.

3. Variables

Renommez .env.example en .env.local. Le quickstart écrit :

NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_... key

Le guide SSR, onglet Next.js, utilise les mêmes noms de variables avec les placeholders supabase_project_url et supabase_publishable_key. Les valeurs viennent de la boîte Connect du projet, onglet frameworks, Next.js. La page API keys explique les types de clés. Ne collez pas la clé secrète dans NEXT_PUBLIC_. Le quickstart ne demande que l’URL et la clé publishable.

4. Démarrer

npm run dev

La page dit d’ouvrir http://localhost:3000 et d’y voir le contenu de app/page.tsx. L’inscription du modèle est à http://localhost:3000/auth/sign-up, bouton Sign up. Nous n’avons pas lancé le serveur le 2026-10-18. Si la page affichée n’est pas app/page.tsx, arrêtez et relisez le modèle, plutôt que d’ajouter une route à la main.

Le quickstart utilise npm run dev. Si vous réinstallez les paquets avec un autre gestionnaire, gardez celui du lockfile du modèle. Le guide SSR documente à part npm install @supabase/supabase-js @supabase/ssr, ainsi que les équivalents yarn add et pnpm add. Cette commande sert au parcours manuel, pas au modèle qui a déjà ses dépendances.

Mot de passe, sans quitter le flux du modèle

L’e-mail et le mot de passe sont activés par défaut, page Password-based Auth. La confirmation d’e-mail est vraie par défaut sur les projets hébergés, fausse par défaut en local ou en auto-hébergement. Le réglage hébergé est sur la page Auth Providers. En local, c’est le fichier de config, clé citée par la doc : auth.email.enable_confirmations.

Avec le SSR, vous êtes sur le flux PKCE, pas sur le flux implicite. La page le dit explicitement. Le flux implicite est le défaut JavaScript et Dart seulement pour du code client seul. Ne copiez pas le snippet implicite dans une app App Router.

Snippet JavaScript du flux implicite, pour voir la forme de l’appel, pas pour le coller dans le serveur :

const { data, error } = await supabase.auth.signUp({
  email: 'valid.email@supabase.io',
  password: 'example-password',
  options: {
    emailRedirectTo: 'https://example.com/welcome',
  },
})

Les adresses et le mot de passe sont les placeholders de la doc. emailRedirectTo doit être une redirect URL configurée dans le tableau de bord, ou dans la config auto-hébergée. Sans redirect, la page dit que l’utilisateur part vers l’URL du site, localhost:3000 par défaut.

Connexion e-mail, même page, JavaScript :

const { data, error } = await supabase.auth.signInWithPassword({
  email: 'valid.email@supabase.io',
  password: 'example-password',
})

Dans le modèle with-supabase, cherchez d’abord si ces appels existent déjà. Les coller une seconde fois dans un client créé autrement casse la session cookie.

Réinitialisation : resetPasswordForEmail ne dit pas si le compte existe. Sans utilisateur, aucun e-mail ne part, et la méthode ne renvoie pas d’erreur pour autant. C’est écrit pour éviter l’énumération. L’exemple JavaScript relu passe redirectTo: 'http://example.com/account/update-password'. Cette URL doit elle aussi être autorisée. La page de changement de mot de passe ne doit être accessible qu’aux personnes déjà authentifiées, puis appeler updateUser.

Le service d’e-mail intégré est limité à 2 e-mails par heure, au mieux, d’après la page relue. Pour la production, la page envoie vers le guide SMTP custom. En local, la CLI capture les e-mails avec Mailpit : supabase status affiche l’URL. Cette page n’a pas lancé la CLI, et n’a pas revu la procédure d’installation de la CLI.

Le téléphone comme identifiant de mot de passe est découragé sur la même page : les numéros sont recyclés. La mitigation indiquée est la MFA. Ce guide ne déroule pas ce flux.

Session côté serveur

Source : Creating a Supabase client for SSR.

Le navigateur et le serveur n’utilisent pas le même client. Les Server Components ne peuvent pas écrire les cookies. Un proxy rafraîchit le jeton en appelant supabase.auth.getClaims(), puis recopie les cookies vers la requête et vers la réponse. Le nom de cookie par défaut, dans l’accordéon relu, est sb- suivi de la référence du projet, puis -auth-token.

Next.js 16 appelle ce fichier proxy.ts. Sur Next.js 15 et avant, un fichier proxy.ts n’est jamais appelé : les sessions ne se rafraîchissent pas et les gens sont déconnectés. L’ancien nom est middleware.ts, fonction middleware. Le code Supabase dedans est le même, dit la note. Vérifiez la version de Next du modèle avant de renommer le fichier.

Retournez l’objet réponse que setAll a construit en dernier. Une réponse plus ancienne n’a pas les cookies rafraîchis. Si vous devez répondre autre chose, la page donne la copie des cookies et des en-têtes cache-control, expires, pragma. Un CDN qui met cette réponse en cache peut connecter la personne suivante avec la session de la précédente. La page le dit pour l’ISR et les CDN. Ne cachez pas une réponse qui pose Set-Cookie.

Ne faites pas confiance à getSession() dans le code serveur, y compris le proxy. Il lit le cookie sans le revérifier. N’importe qui peut forger ce cookie. getClaims() vérifie la signature à chaque appel. Sur les projets à clés asymétriques, défaut des nouveaux projets, la vérif est locale contre les clés publiques en cache. Sur un secret symétrique, l’appel part vers Auth. getUser() sert quand il vous faut la fiche utilisateur à jour : cet appel interroge Auth, il ne se contente pas du cookie.

Un refresh token ne s’utilise en général qu’une fois. La page décrit deux exceptions, dont la fenêtre courte de l’aller-retour SSR. Un réemploi hors de ces cas révoque toute la session. Le symptôme ressemble à des déconnexions au hasard. Deux rafraîchissements en parallèle sont le cas cité.

Le quickstart vous dit d’avoir fini quand l’app tourne. Le guide SSR vous dit de copier lib/supabase/client.ts, server.ts et le proxy depuis ses onglets. Si le modèle a déjà un dossier d’utilitaires, ne créez pas le second à côté. La page rendue le 2026-10-18 pointait un exemple proxy.ts dans le dépôt Supabase. Suivez le lien de la doc du jour, pas un commit figé dans un article.

Le flux PKCE manuel, page mots de passe, ajoute un modèle d’e-mail avec token_hash et une route app/auth/confirm/route.ts qui appelle verifyOtp. Cette route importe @/utils/supabase/server. Le guide SSR parle de lib/supabase. Le modèle quickstart a son propre arbre. Gardez-en un seul. Cette route n’a pas été compilée le 2026-10-18.

Ce qui n’a pas été fait

Pas de projet créé, pas de npm run dev, pas d’inscription, pas de Mailpit ouvert. Les commandes n’ont pas été rejouées le 2026-10-18. Si localhost:3000 ne montre pas ce que le quickstart annonce, le décalage vient du modèle ou de votre version de Next, pas d’une capture absente de cette page.

Sources et limites