Passkey et WebAuthn : login sans mot de passe, sans magie
· 5 min read · Filippo Spinella · Security, WebAuthn, Authentication, Web Development
Les mots de passe font partie de ces choses que nous avons normalisées simplement parce que nous vivons avec eux depuis des années. Les utilisateurs les oublient, les réutilisent, les écrivent là où ils ne devraient pas. Les équipes doivent gérer les réinitialisations, les politiques, les hachages, les fuites, le phishing et le support.
Les passkey ne rendent pas l'authentification parfaite, mais ils suppriment un énorme problème : le serveur n'a plus besoin de garder un secret partagé avec l'utilisateur.
Que se passe-t-il réellement
Un passkey est un identifiant basé sur WebAuthn. Lorsque l'utilisateur le crée, l'appareil génère une bi-clé :
- une clé privée, qui reste sur l'appareil ou dans le gestionnaire de mots de passe ;
- une clé publique, que le serveur peut sauvegarder.
Lors de la connexion, le serveur ne demande pas "dites-moi le mot de passe". Envoyez un défi aléatoire. L'appareil le signe avec la clé privée. Le serveur vérifie la signature avec la clé publique.
C'est ce qui est intéressant : si la base de données est volée, il n'y a aucun mot de passe à déchiffrer. Et si un utilisateur se retrouve sur un faux domaine, le passkey n'est pas valable pour ce domaine. Ce n'est pas seulement une question de commodité, c'est une protection concrète contre le phishing.
Le navigateur fait office de pont
Dans le navigateur, les deux API principaux sont :
navigator.credentials.create()pour créer un passkey ;navigator.credentials.get()pour l'utiliser lors de la connexion.
Mais la logique importante réside dans le serveur. Le serveur doit générer le challenge, le sauvegarder temporairement, vérifier la réponse, vérifier la source et Relying Party ID, puis créer la session.
La partie client devrait être presque ennuyeuse :
const options = await fetch('/api/passkeys/login/options').then((r) => r.json()); const credential = await navigator.credentials.get({ publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options), }); await fetch('/api/passkeys/login/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credential?.toJSON()), });
Si vous vous retrouvez à mettre en œuvre le chiffrement WebAuthn à la main, arrêtez. Utilisez une bibliothèque robuste côté serveur. Les erreurs ici ne sont pas des "bugs mignons", ce sont des trous d'authentification.
Que sauvegarder dans la base de données
Il n’est pas nécessaire de sauver la moitié du monde. Généralement suffisant :
- ID du titre de compétences ;
- clé publique ;
- utilisateur connecté ;
- tout compteur de vérification ou métadonnées ;
- les transports, si utiles pour l'UX ;
- nom choisi par l'utilisateur ;
- date de création et dernière utilisation.
Un tableau minimal pourrait ressembler à ceci :
create table passkey_credentials ( id uuid primary key default gen_random_uuid(), user_id uuid not null references users(id), credential_id text not null unique, public_key text not null, name text, created_at timestamptz not null default now(), last_used_at timestamptz );
Ensuite, j'ajouterais des journaux d'audit et des notifications : si quelqu'un crée un nouveau passkey sur mon compte, je veux en être informé.
L'UX compte plus que la démo
La démo d'un passkey est toujours belle : vous cliquez, Face ID, vous y êtes. Le produit lui-même est plus compliqué.
Quelqu'un change de téléphone. Quelqu'un utilise un ordinateur d'entreprise verrouillé. Certaines personnes ne comprennent pas pourquoi le navigateur suggère un passkey. Quelqu'un perd l'accès à son appareil.
C'est pourquoi je ne commencerais pas par "à partir d'aujourd'hui, plus de mots de passe pour tout le monde". Je commencerais comme ça :
- passkey facultatif pour les utilisateurs internes ;
- suggestion d'en créer un après une connexion réussie ;
- page du compte pour renommer et supprimer passkey ;
- repli clair ;
- déploiement progressif dans la connexion principale.
Le texte dans l'interface doit être simple. "Utilisez l'écran de verrouillage de votre appareil" est préférable à "authentifiez-vous avec un identifiant de résident FIDO2".
Erreurs que j'éviterais
Ne génèrez pas de défis sur le client. Le challenge est créé sur le serveur et ne doit être vérifié qu'une seule fois.
Ne vous contentez pas de l'identifiant des informations d'identification. Vous devez vérifier la signature, le défi, l'origine et le Relying Party ID.
Ne supprimez pas les solutions de secours avant d'avoir un bon flux de récupération. Le sans mot de passe ne doit pas nécessairement devenir « si vous perdez votre téléphone, vous êtes absent pour toujours ».
Ne traitez pas le passkey comme un bouton purement frontal. Cacher un bouton n’est pas une question de sécurité : la véritable vérification se fait côté serveur.
Passkey-first ou passkey-friendly ?
Pour un nouveau produit, vous pouvez penser d'abord passkey. Pour une application existante, je préfère la compatibilité passkey : ajoutez passkey comme méthode recommandée, mesurez le succès et les problèmes, puis réduisez calmement le poids du mot de passe.
La migration idéale ne se fait pas sentir. L'utilisateur découvre que la connexion est plus facile, mais que l'entreprise n'a pas modifié son protocole d'authentification.
Conclusion
Les passkey sont intéressants car ils améliorent à la fois la sécurité et l’UX, ce qui est rare. Ce n’est pas une baguette magique : la récupération, la compatibilité, le support et le déploiement restent à bien concevoir.
Mais le changement fondamental est fort. Arrêtez de demander aux utilisateurs d’inventer et de protéger des secrets. Vous laissez l'appareil signer une preuve cryptographique liée à votre domaine. Moins de mémoire humaine, moins de phishing, moins de réinitialisations de mots de passe. Je dirais qu'ils valent la peine d'être pris au sérieux.
##Sources