📍 Article principal : Supabase 2026 : guide pratique.
Supabase Auth = GoTrue. Email/password, magic links, OAuth, SMS OTP, JWT. Ce tutoriel détaille la configuration validée pour SaaS B2B et apps mobile francophones.
Prérequis
- Supabase en production (voir tutoriel installation).
- SMTP configuré pour magic links.
- OAuth providers credentials (Google, GitHub, etc).
- Niveau : intermédiaire.
- Temps : 1-2h.
Pour utiliser Supabase Auth, vous avez besoin d’un projet Supabase actif (gratuit jusqu’à 50 000 MAU = monthly active users). Le SDK supabase-js v2 ou la lib correspondante (Dart, Python, Swift selon votre plateforme). Un domaine pour les redirect URLs (configurable même sur le plan gratuit). Pour les SMS OTP en zone UEMOA, un provider Twilio ou MessageBird configuré (Supabase ne fournit pas la livraison SMS, vous l’apportez via l’option custom SMTP/SMS).
Étape 1 — Email/Password
Studio → Authentication → Providers → Email. Activer. Configurer :
- Confirm email : ON (obligatoire production).
- Min password length : 12.
- Password requirements : alpha + digits.
L’inscription email/password classique tient en deux lignes : const { data, error } = await supabase.auth.signUp({ email, password }). Supabase envoie automatiquement un email de confirmation (templatable dans le dashboard). L’utilisateur clique le lien et son compte est confirmé. Pour la connexion : signInWithPassword({ email, password }) qui retourne une session avec access_token JWT et refresh_token. Stockez la session côté client via le SDK qui gère le localStorage automatiquement.
Étape 2 — Magic Links
Email link unique sans password. UX moderne :
const { error } = await supabase.auth.signInWithOtp({
email: 'amadou@example.com',
options: {
emailRedirectTo: 'https://votre-app.com/dashboard'
}
});
User reçoit email avec lien magic. Clic = connecté.
Les magic links éliminent les mots de passe. supabase.auth.signInWithOtp({ email }) envoie un lien à usage unique valide 1 heure (configurable). Le clic du lien authentifie l’utilisateur sans demander de mot de passe. Idéal pour les apps B2B où la friction de mémorisation de mot de passe pousse à l’abandon. Pour une PME à Sicap Liberté qui héberge un portail client, les magic links combinés à l’email pré-rempli divisent le taux d’abandon par 2-3 par rapport au formulaire mot de passe classique.
Étape 3 — OAuth Google
Console Google Cloud → APIs & Services → Credentials → OAuth 2.0 Client IDs → Web application :
- Authorized redirect URIs :
https://api.votre-app.com/auth/v1/callback.
Copier client_id et client_secret. Studio Supabase → Auth → Providers → Google → Enable + paste.
const { error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: 'https://votre-app.com/dashboard' }
});
Étape 4 — OAuth GitHub
GitHub → Settings → Developer settings → OAuth Apps → New :
- Authorization callback URL :
https://api.votre-app.com/auth/v1/callback.
Copier credentials dans Studio.
OAuth GitHub permet aux développeurs de se connecter avec leur compte GitHub existant. Dans Supabase Dashboard → Authentication → Providers → GitHub, activez et configurez Client ID et Secret depuis github.com/settings/developers. Côté code : supabase.auth.signInWithOAuth({ provider: 'github', options: { redirectTo: 'https://app.example.sn/auth/callback' } }). L’utilisateur est redirigé vers GitHub, autorise l’app, revient avec une session. Particulièrement adapté pour les outils dev (knowledge base technique, plateforme tutoriels code).
Étape 5 — OAuth Apple (iOS)
Apple Developer Account → Certificates, IDs & Profiles → Service IDs. Configuration plus complexe (private key .p8). Documentation Supabase détaillée.
OAuth Apple (Sign in with Apple) est obligatoire dans l’App Store si vous proposez d’autres OAuth providers. Configurez dans Apple Developer Portal puis Supabase → Authentication → Providers → Apple. Ajoutez les Service ID et Team ID. Côté Swift natif, utilisez ASAuthorizationAppleIDProvider qui retourne un JWT que vous échangez avec Supabase via signInWithIdToken. Apple impose des contraintes strictes sur le naming et l’icône du bouton (suivez les Apple HIG pour éviter le rejet en review).
Étape 6 — SMS OTP via Twilio
Pour app mobile Afrique de l’Ouest, SMS OTP via Twilio :
- Twilio account → Verify Service.
- Studio Supabase → Auth → Providers → Phone → Twilio + credentials.
const { error } = await supabase.auth.signInWithOtp({
phone: '+221700000000'
});
// User reçoit SMS code 6 chiffres
const { error } = await supabase.auth.verifyOtp({
phone: '+221700000000',
token: '123456',
type: 'sms'
});
Étape 7 — Session management
// Get current user
const { data: { user } } = await supabase.auth.getUser();
// Listen auth changes
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_IN') router.push('/dashboard');
if (event === 'SIGNED_OUT') router.push('/login');
});
// Sign out
await supabase.auth.signOut();
Supabase gère automatiquement la rotation des tokens. L’access_token expire après 1 heure (configurable), le refresh_token après 30 jours. Le SDK rafraîchit silencieusement avant expiration. Pour les apps SSR (Next.js), utilisez @supabase/ssr v0.5+ qui gère les cookies HTTPOnly côté serveur. Surveillez l’événement onAuthStateChange pour réagir aux SIGNED_IN, SIGNED_OUT, TOKEN_REFRESHED. Pour la sécurité critique (banque), réduisez l’access_token TTL à 15 minutes pour limiter la fenêtre d’exploitation en cas de fuite.
Étape 8 — JWT custom claims
Pour ajouter role/org dans JWT :
CREATE OR REPLACE FUNCTION add_user_meta_data() RETURNS trigger AS $$
BEGIN
NEW.raw_user_meta_data = NEW.raw_user_meta_data || jsonb_build_object(
'role', (SELECT role FROM profiles WHERE id = NEW.id),
'org_id', (SELECT organization_id FROM profiles WHERE id = NEW.id)
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Pour ajouter des claims custom au JWT (rôle utilisateur, organisation_id, plan tarifaire), utilisez les Auth Hooks Supabase introduits en 2024. Créez une Edge Function ou un trigger Postgres qui ajoute des claims au moment de l’authentification : app_metadata: { role: 'admin', org_id: 'xyz' }. Ces claims sont vérifiables dans les Row Level Security policies via auth.jwt(). Pour une app multi-tenant, le claim org_id permet de filtrer automatiquement les données par tenant sans code applicatif.
Étape 9 — Password reset
// Demande reset
await supabase.auth.resetPasswordForEmail('email@example.com', {
redirectTo: 'https://votre-app.com/reset-password'
});
// Page reset
await supabase.auth.updateUser({ password: 'new-password' });
Le flow de reset password : supabase.auth.resetPasswordForEmail(email, { redirectTo: 'https://app.example.sn/reset' }) envoie un email avec un lien temporaire. Sur la page /reset, l’utilisateur saisit son nouveau mot de passe et appelle supabase.auth.updateUser({ password: newPassword }). Le SDK valide la session de reset et applique le changement. Limitez les tentatives via les rate limits Supabase Auth (5 par heure par email par défaut) pour éviter les attaques de type email bombing.
Étape 10 — MFA TOTP (optionnel)
Supabase 2.0+ supporte MFA TOTP. Config Studio → Auth → MFA → Enable.
L’authentification multi-facteurs TOTP (Google Authenticator, Authy) renforce les comptes admin. Activez via supabase.auth.mfa.enroll({ factorType: 'totp' }) qui retourne un QR code à scanner. L’utilisateur saisit le code à 6 chiffres pour valider l’enrollment. À chaque connexion, après le mot de passe, demandez le code TOTP via verify({ factorId, challengeId, code }). Pour une fintech à Plateau qui héberge des données financières, MFA est non négociable sur tous les comptes admin.
Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| Magic link redirect échec | URL not whitelisted | Auth → URL Configuration → add Site URL |
| OAuth callback 404 | Redirect URI mismatch | URL exacte côté Google/GitHub |
| SMTP fail | Variables non chargées | Restart auth container |
| SMS Twilio coût | +221 cher | Vérifier pricing par pays |
| Session pas persistée | localStorage manquant | SDK auto, vérifier persistSession |
| JWT expiry trop court | 1h défaut | JWT_EXP variable env |
Mise en œuvre dans le contexte sénégalais
Quatre précisions. SMS OTP coût : Twilio +221 ~0.05 USD/SMS. Pour 1000 OTP/mois = 50 USD. Africa SMS provider Africa’s Talking peut être moins cher. Magic links : préféré sur SMS pour éviter coût. Email arrive aussi rapidement. OAuth Google : 90% des Africains francophones ont compte Gmail. UX login en 2 clics. Apple Sign In : moins prévalent en Afrique mais obligatoire pour App Store iOS.
Tutoriels frères
Supabase Auth se complète bien avec les autres modules Supabase. Database (Postgres) avec Row Level Security exploite les claims JWT pour filtrer les données par utilisateur. Storage utilise les mêmes policies pour autoriser ou refuser les uploads/downloads. Edge Functions reçoivent automatiquement le JWT vérifié pour exécuter du code authentifié. Realtime (websockets) respecte aussi les RLS. Cette intégration end-to-end évite la dispersion entre 5 services SaaS (Auth0, Cloudinary, Vercel Edge, Pusher).
FAQ
WhatsApp OTP ? Pas natif. Custom integration via Twilio WhatsApp ou Meta Business API.
Multi-factor mandatory ? Non par défaut. Activable par utilisateur.
Auth UI ready-made ? @supabase/auth-ui-react component prêt à l’emploi.
Session refresh auto ? Oui SDK refresh tokens auto.
Migration depuis Auth0/Firebase ? Outils communautaires + JWT generation custom.
Sur un angle proche
- 🔝 guide général : guide pratique Supabase 2026
- Documentation Auth : supabase.com/docs/guides/auth
Pour creuser l’authentification, voyez nos tutoriels Authentik self-hosted (alternative open-source si vous voulez la souveraineté), Clerk pour les apps B2B avec besoins UI premium, Auth.js (NextAuth) pour les projets Next.js mono-stack. Le choix dépend du contexte : Supabase si vous utilisez déjà la stack Supabase, Authentik si vous self-héberger toute la stack, Clerk si le budget permet et que l’UX prime.
Pourquoi combiner OAuth et magic links plutot que mot de passe
L’authentification par mot de passe reste la principale source de comptes pirates : reutilisation entre sites, phishing, fuites de bases. Pour une PME a Dakar, Abidjan ou Lome qui lance une app SaaS, supprimer le mot de passe c’est supprimer 80 % des incidents support et de la surface de risque. OAuth (Google, GitHub, Microsoft) reduit la friction pour les utilisateurs deja equipes ; les magic links par email couvrent ceux qui n’ont pas de compte Google ou prefer ne pas le lier.
Supabase offre les deux nativement, sans serveur backend. Le plan Free supporte 50 000 utilisateurs actifs mensuels et l’envoi d’emails par le service interne (limite a 4 emails par heure et par utilisateur, suffisant pour une phase de demarrage). Au-dela, on branche un fournisseur SMTP comme Resend, Brevo ou AWS SES.
Etape 1 : Creer le projet Supabase et activer les providers
Sur supabase.com, creez un projet dans la region la plus proche (Frankfurt eu-central-1 pour l’Afrique de l’Ouest, latence moyenne 80-120 ms). Dans Authentication, onglet Providers, vous voyez la liste : Email, Phone, Google, GitHub, Apple, Discord, Twitter, Facebook, Microsoft, etc.
Activez Email pour les magic links, et Google + GitHub pour le demarrage. Chaque provider OAuth demande un Client ID et Client Secret obtenus chez le fournisseur (console.cloud.google.com pour Google, github.com/settings/developers pour GitHub).
Etape 2 : Configurer Google OAuth
Sur Google Cloud Console, creez un projet, activez l’API « Google+ API » puis OAuth consent screen, type External. Renseignez le nom de l’app, l’email de support et le domaine autorise (votre domaine custom ou xyz.supabase.co).
Onglet Credentials, Create Credentials, OAuth client ID, type Web application. Dans Authorized redirect URIs, ajoutez l’URL fournie par Supabase (visible dans le panneau du provider Google) : https://xyz.supabase.co/auth/v1/callback.
# Copiez Client ID et Client Secret dans Supabase
# Authentication > Providers > Google
# Activez le toggle puis collez les deux valeurs et Save
Le bouton Save valide. Si l’URL de redirection ne correspond pas, Google renvoie une erreur 400 redirect_uri_mismatch lors du premier test : copiez l’URL exacte affichee par Supabase, sans espace ni slash final.
Etape 3 : Configurer GitHub OAuth
Sur github.com, Settings, Developer settings, OAuth Apps, New OAuth App. Application name = votre PME, Homepage URL = https://votre-app.com, Authorization callback URL = https://xyz.supabase.co/auth/v1/callback.
Cliquez Register application, generez un Client Secret (visible une seule fois, copiez immediatement). Collez Client ID et Secret dans Supabase. Sauvegardez. Cote utilisateur, le premier login GitHub affichera l’ecran de consentement avec votre nom d’app et l’icone que vous avez uploadee.
Etape 4 : Activer les magic links dans Supabase
Dans Authentication, onglet Providers, cliquez Email. Le toggle Enable email provider doit etre actif. Activez aussi Confirm email (oblige a cliquer un lien avant de pouvoir se connecter, evite la creation de comptes avec des emails fictifs).
Onglet Email Templates, personnalisez le template Magic Link en francais. La variable {{ .ConfirmationURL }} est obligatoire ; elle contient le lien signe valide 1 heure par defaut.
<h2>Connexion a votre compte</h2>
<p>Cliquez sur le lien ci-dessous pour vous connecter. Ce lien expire dans 1 heure.</p>
<a href="{{ .ConfirmationURL }}">Se connecter</a>
<p>Si vous n'avez pas demande cette connexion, ignorez cet email.</p>
Sauvegardez. Le template par defaut en anglais est remplace pour tous les futurs envois. Pensez a tester en vous envoyant un magic link a vous-meme depuis Authentication, Users, Add user, Send magic link.
Etape 5 : Integrer le client JavaScript
Cote frontend, installez le SDK officiel : npm install @supabase/supabase-js@2. Initialisez le client dans un fichier supabaseClient.js avec l’URL et la cle anon visibles dans Settings, API.
import { createClient } from '@supabase/supabase-js'
export const supabase = createClient(
'https://xyz.supabase.co',
'eyJhbGciOiJI...' // anon key publique
)
La cle anon est publique et limitee par les Row Level Security policies. Ne mettez jamais la service_role key cote frontend : elle bypasse RLS et expose toute la base.
Etape 6 : Bouton « Se connecter avec Google »
Dans votre composant React, Vue ou vanilla JS, declenchez le flow OAuth en un appel.
async function loginGoogle() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: 'https://votre-app.com/dashboard' }
})
if (error) console.error(error.message)
}
Le navigateur redirige vers Google, l’utilisateur valide, Google renvoie vers Supabase, Supabase cree la session et redirige vers /dashboard. La session est stockee dans localStorage par defaut. A l’arrivee sur /dashboard, recuperez l’utilisateur avec supabase.auth.getUser().
Etape 7 : Formulaire magic link
Pour les utilisateurs sans compte Google, un simple champ email suffit.
async function sendMagicLink(email) {
const { error } = await supabase.auth.signInWithOtp({
email,
options: { emailRedirectTo: 'https://votre-app.com/dashboard' }
})
if (error) alert(error.message)
else alert('Verifiez votre boite mail !')
}
L’utilisateur recoit l’email en quelques secondes. Le lien le redirige vers /dashboard avec une session active. Si l’email tombe en spam (frequent depuis le SMTP Supabase mutualise), c’est le signal pour brancher Resend ou Brevo en SMTP custom.
Etape 8 : Brancher un SMTP custom (Resend)
Inscrivez-vous sur resend.com (3000 emails par mois gratuits, 20 USD/mois pour 50 000). Verifiez votre domaine d’envoi via DNS (3 enregistrements TXT et MX). Generez une API key.
Dans Supabase, Settings, Authentication, scroll jusqu’a SMTP Settings. Renseignez : Host = smtp.resend.com, Port = 465, Username = resend, Password = votre API key, Sender email = noreply@votre-domaine.com. Sauvegardez et envoyez un test depuis Authentication, Users.
Etape 9 : Proteger les routes avec RLS
L’auth ne sert a rien si vos tables sont accessibles a tous. Pour chaque table sensible, activez Row Level Security et creez une policy.
-- Dans le SQL editor Supabase
alter table profiles enable row level security;
create policy "Users can read own profile"
on profiles for select
using ( auth.uid() = id );
create policy "Users can update own profile"
on profiles for update
using ( auth.uid() = id );
Testez : depuis le frontend, un select * from profiles ne retourne que la ligne de l’utilisateur connecte. Sans policy, RLS bloque tout par defaut, ce qui est le comportement souhaite (fail closed).
Voir aussi notre guide Supabase Storage et notre tutoriel PocketBase hooks Go.