Authentification passwordless avec Auth0 : email magic links et SMS OTP

Supprimez les mots de passe de votre application. Auth0 Passwordless avec magic links email et SMS OTP : implémentation, UX et considérations de sécurité.

Par Auth0.Expert · 2025-04-28 · 9 min de lecture

Passwordless Magic Links UX

Authentification passwordless avec Auth0

TL;DR

Les mots de passe sont responsables de 81% des violations de données. L'authentification passwordless (magic links, OTP) élimine ce vecteur d'attaque tout en simplifiant l'expérience utilisateur.

---

Passwordless vs Mot de passe

Voici un comparatif rapide entre la connexion par mot de passe et les méthodes passwordless sur divers critères de sécurité et d’expérience utilisateur.

| Critère | Mot de passe | Magic Link | SMS OTP | |---------|-------------|------------|---------| | Facilité utilisateur | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | | Risque credential stuffing | ⭐ (élevé) | ✅ Éliminé | ✅ Éliminé | | Risque phishing | ⭐ (élevé) | ⚠️ Partiel | ⚠️ Partiel | | Dépendance infrastructure | ❌ | Email (99.9%) | SMS (98%) | | SIM swapping | N/A | N/A | ⚠️ Risque |

---

Activer Passwordless dans Auth0

Voici comment activer les connexions passwordless (magic link ou OTP) dans Auth0 via le dashboard, afin d’offrir une expérience sans mot de passe à vos utilisateurs.

{
  "email": {
    "enabled": true,
    "syntax": "link",     // "link" pour magic link, "code" pour OTP
    "from": "[email protected]",
    "subject": "Votre lien de connexion",
    "template": "..."
  },
  "sms": {
    "enabled": true,
    "provider": "twilio",
    "from": "+33XXXXXXXXX"
  }
}

---

Implémentation : Magic Link (email)

Ce bloc montre l’appel à l’API Auth0 pour demander un magic link à envoyer par email, initialisant le flow d’authentification passwordless.

// 1. Demander un magic link
async function requestMagicLink(email) {
  const response = await fetch('https://YOUR_DOMAIN.auth0.com/passwordless/start', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: CLIENT_ID,
      connection: 'email',
      email: email,
      send: 'link',         // "link" ou "code"
      authParams: {
        scope: 'openid email',
        redirect_uri: 'https://yourapp.com/callback',
      },
    }),
  });
  return response.ok;
}

// 2. Auth0 envoie l'email
// 3. Utilisateur clique → callback avec code
// 4. Échanger le code contre un token (flow normal PKCE)

Ce code déclenche l’envoi d’un magic link, et prépare le flow OAuth pour authentifier l’utilisateur sans mot de passe.

---

Implémentation : OTP (email ou SMS)

Ce bloc illustre la demande d’un OTP via email ou SMS, puis la vérification du code saisi pour obtenir un access token Auth0.

// Étape 1 : Demander l'OTP
async function requestOTP(emailOrPhone, channel) {
  const body = channel === 'email'
    ? { connection: 'email', email: emailOrPhone, send: 'code' }
    : { connection: 'sms', phone_number: emailOrPhone, send: 'code' };

  await fetch('https://YOUR_DOMAIN.auth0.com/passwordless/start', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Auth0-Client': btoa(JSON.stringify({name: 'yourapp', version: '1.0.0'})),
    },
    body: JSON.stringify({ client_id: CLIENT_ID, ...body }),
  });
}

// Étape 2 : Vérifier l'OTP
async function verifyOTP(emailOrPhone, otp, channel) {
  const body = channel === 'email'
    ? { connection: 'email', email: emailOrPhone }
    : { connection: 'sms', username: emailOrPhone };

  const response = await fetch('https://YOUR_DOMAIN.auth0.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',
      client_id: CLIENT_ID,
      otp: otp,
      scope: 'openid email',
      ...body,
    }),
  });
  return response.json(); // { access_token, id_token, ... }
}

Ce code gère tout le cycle de la demande et vérification OTP, permettant à un utilisateur de s'authentifier par email ou SMS sans mot de passe.

---

Composant React : formulaire passwordless

Dans cette section, on présente un formulaire React permettant à un utilisateur de se connecter en passwordless, avec gestion de l’envoi d’OTP et de la vérification côté client.

function PasswordlessLogin() {
  const [step, setStep] = useState('email'); // 'email' | 'otp' | 'success'
  const [email, setEmail] = useState('');
  const [otp, setOtp] = useState('');
  const [loading, setLoading] = useState(false);

  const handleEmailSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    await requestOTP(email, 'email');
    setStep('otp');
    setLoading(false);
  };

  const handleOTPSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    const tokens = await verifyOTP(email, otp, 'email');
    if (tokens.access_token) {
      // Stocker les tokens et rediriger
      setStep('success');
    }
    setLoading(false);
  };

  if (step === 'email') return (
    <form onSubmit={handleEmailSubmit}>
      <input
        type="email"
        value={email}
        onChange={e => setEmail(e.target.value)}
        placeholder="[email protected]"
        required
      />
      <button type="submit" disabled={loading}>
        {loading ? 'Envoi...' : 'Envoyer le code'}
      </button>
    </form>
  );

  if (step === 'otp') return (
    <form onSubmit={handleOTPSubmit}>
      <p>Code envoyé à {email}</p>
      <input
        type="text"
        value={otp}
        onChange={e => setOtp(e.target.value.replace(/\D/g, '').slice(0, 6))}
        placeholder="123456"
        inputMode="numeric"
        pattern="[0-9]{6}"
        required
      />
      <button type="submit" disabled={loading || otp.length < 6}>
        Vérifier
      </button>
      <button type="button" onClick={() => setStep('email')}>
        Changer d'email
      </button>
    </form>
  );

  return <div>Connecté !</div>;
}

Ce composant React gère l’envoi du code, la vérification OTP et le passage visuel entre étapes, facilitant l’onboarding passwordless côté front-end.

---

Sécurité des magic links

Cette section décrit les points de sécurité pour l’utilisation des magic links avec Auth0.

Mitigation : combiner passwordless email + facteur de connaissance (PIN) pour les accès très sensibles.

---

Template email personnalisé

Ce modèle HTML permet de personnaliser le contenu de l’email envoyé lors d’une authentification passwordless, rendant l’expérience utilisateur plus claire et sécurisée.

<!-- Dashboard → Branding → Email Templates → Passwordless Email -->
<p>Bonjour,</p>
<p>Cliquez sur ce lien pour vous connecter à {{ application.name }} :</p>
<a href="{{ link }}" style="background:#7C3AED;color:white;padding:12px 24px;border-radius:8px;text-decoration:none;">
  Se connecter
</a>
<p>Ce lien expire dans 5 minutes.</p>
<p>Si vous n'avez pas demandé ce lien, ignorez cet email.</p>

---

> 🚀 Migration vers passwordless : nous concevons et déployons votre stratégie de suppression des mots de passe avec un accompagnement au changement pour vos utilisateurs.

📞 +33 1 23 45 67 89 · 📧 [email protected]


Autres articles