Se connecter avec une clé d'accès via le remplissage automatique de formulaire

Créez une expérience de connexion qui exploite les clés d'accès tout en prenant en charge les utilisateurs de mots de passe existants.

Les clés d'accès remplacent les mots de passe et rendent les comptes utilisateur sur le Web plus sûrs, plus simples et plus faciles à utiliser. Toutefois, le passage d'une authentification par mot de passe à une authentification basée sur des clés d'accès peut compliquer l'expérience utilisateur. Utiliser le remplissage automatique de formulaire pour suggérer des clés d'accès peut contribuer à créer une expérience unifiée.

Pourquoi utiliser le remplissage automatique des formulaires pour se connecter avec une clé d'accès ?

Avec une clé d'accès, un utilisateur peut se connecter à un site Web en utilisant simplement son empreinte digitale, son visage ou le code de son appareil.

Dans l'idéal, il n'y aurait pas d'utilisateur de mot de passe et le flux d'authentification pourrait être aussi simple qu'un bouton de connexion unique. Lorsque l'utilisateur appuie sur le bouton, une boîte de dialogue de sélection de compte s'affiche. Il peut choisir un compte, déverrouiller l'écran pour le valider et s'y connecter.

Cependant, passer d'une authentification par mot de passe à une authentification basée sur des clés d'accès peut s'avérer difficile. Lorsque les utilisateurs passeront à des clés d'accès, ceux qui utilisent des mots de passe et des sites Web devront toujours prendre en charge ces deux types d'utilisateurs. On ne s'attend pas à ce que les utilisateurs se souviennent eux-mêmes des sites sur lesquels ils sont passés aux clés d'accès. Par conséquent, demander aux utilisateurs de sélectionner dès le départ la méthode à utiliser serait une mauvaise expérience utilisateur.

Les clés d'accès sont également une nouvelle technologie. Les expliquer et s'assurer que les utilisateurs sont à l'aise avec leur utilisation peut être un défi pour les sites Web. Nous pouvons nous appuyer sur des expériences utilisateur familières pour la saisie automatique des mots de passe afin de résoudre ces deux problèmes.

UI conditionnelle

Pour créer une expérience utilisateur efficace pour les utilisateurs de clés d'accès et de mots de passe, vous pouvez inclure des clés d'accès dans les suggestions de saisie automatique. C'est ce qu'on appelle l'UI conditionnelle. Elle fait partie de la norme WebAuthn.

Dès que l'utilisateur appuie sur le champ de saisie du nom d'utilisateur, une boîte de dialogue de suggestion de saisie automatique s'affiche. Elle met en surbrillance les clés d'accès stockées et propose des suggestions de saisie automatique de mots de passe. L'utilisateur peut ensuite choisir un compte et utiliser le verrouillage de l'écran de l'appareil pour se connecter.

De cette façon, les utilisateurs peuvent se connecter à votre site Web avec le formulaire existant, comme si rien n'avait changé, mais en bénéficiant des avantages de sécurité supplémentaires des clés d'accès, le cas échéant.

Fonctionnement

Pour vous authentifier avec une clé d'accès, utilisez l'API WebAuthn.

Les quatre composants d'un flux d'authentification par clé d'accès sont les suivants : l'utilisateur:

  • Backend: votre serveur backend qui contient la base de données des comptes stockant la clé publique et d'autres métadonnées concernant la clé d'accès.
  • Interface: votre interface qui communique avec le navigateur et envoie des requêtes de récupération au backend.
  • Navigateur: navigateur de l'utilisateur qui exécute votre code JavaScript.
  • Authenticator: authentificateur de l'utilisateur qui crée et stocke la clé d'accès. Celle-ci peut se trouver sur le même appareil que le navigateur (lorsque vous utilisez Windows Hello, par exemple) ou sur un autre appareil, comme un téléphone.
Diagramme de l'authentification par clé d'accès
  1. Dès qu'un utilisateur accède à l'interface, il demande au backend de s'authentifier avec une clé d'accès et appelle navigator.credentials.get() pour lancer l'authentification avec une clé d'accès. Cela renvoie un Promise.
  2. Lorsque l'utilisateur place le curseur dans le champ de connexion, le navigateur affiche une boîte de dialogue de saisie automatique de mot de passe contenant les clés d'accès. Une boîte de dialogue d'authentification s'affiche si l'utilisateur sélectionne une clé d'accès.
  3. Une fois que l'utilisateur a validé son identité à l'aide du verrouillage de l'écran de l'appareil, la promesse est résolue et des identifiants de clé publique sont renvoyés à l'interface.
  4. L'interface envoie les identifiants de la clé publique au backend. Le backend vérifie la signature par rapport à la clé publique du compte correspondant dans la base de données. Si l'opération réussit, l'utilisateur est connecté.

Conditions préalables

L'UI WebAuthn conditionnelle est publiquement prise en charge dans Safari sur iOS 16, iPadOS 16 et macOS Ventura. Il est également disponible sur Chrome sur Android, macOS et Windows 11 22H2.

S'authentifier avec une clé d'accès via le remplissage automatique de formulaire

Lorsqu'un utilisateur souhaite se connecter, vous pouvez effectuer un appel get WebAuthn conditionnel pour indiquer que des clés d'accès peuvent être incluses dans les suggestions de saisie automatique. Un appel conditionnel à l'API navigator.credentials.get() de WebAuthn n'affiche pas l'UI et reste en attente jusqu'à ce que l'utilisateur sélectionne un compte avec lequel se connecter à partir des suggestions de saisie automatique. Si l'utilisateur choisit une clé d'accès, le navigateur résoudra la promesse avec un identifiant au lieu de remplir le formulaire de connexion. Il incombe alors à la page de connecter l'utilisateur.

Champ de saisie "Annoter le formulaire"

Si nécessaire, ajoutez un attribut autocomplete au champ input (nom d'utilisateur). Ajoutez username et webauthn comme jetons pour lui permettre de suggérer des clés d'accès.

<input type="text" name="username" autocomplete="username webauthn" ...>

Détection de caractéristiques

Avant d'appeler un appel d'API WebAuthn conditionnel, vérifiez les points suivants:

  • Le navigateur est compatible avec WebAuthn.
  • Le navigateur est compatible avec l'UI conditionnelle WebAuthn.
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  
if (window.PublicKeyCredential &&  
    PublicKeyCredential.​​isConditionalMediationAvailable) {  
  // Check if conditional mediation is available.  
  const isCMA = await PublicKeyCredential.​​isConditionalMediationAvailable();  
  if (isCMA) {  
    // Call WebAuthn authentication  
  }  
}  

Récupérer une question d'authentification sur le serveur du tiers assujetti à des restrictions

Récupérez une question d'authentification auprès du serveur RP requis pour appeler navigator.credentials.get():

  • challenge : question d'authentification générée par le serveur dans un objet ArrayBuffer. Cela est nécessaire pour éviter les attaques par rejeu. Assurez-vous de générer une nouvelle question d'authentification à chaque tentative de connexion et ignorez-la après un certain délai ou après l'échec de la validation d'une tentative de connexion. Considérez-la comme un jeton CSRF.
  • allowCredentials : tableau d'identifiants acceptables pour cette authentification. Transmettez un tableau vide pour permettre à l'utilisateur de sélectionner une clé d'accès disponible dans une liste affichée par le navigateur.
  • userVerification : indique si la validation de l'utilisateur à l'aide du verrouillage de l'écran de l'appareil est "required", "preferred" ou "discouraged". La valeur par défaut est "preferred", ce qui signifie que l'authentificateur peut ignorer la validation de l'utilisateur. Définissez ce paramètre sur "preferred" ou omettez la propriété.

Appeler l'API WebAuthn avec l'option conditional pour authentifier l'utilisateur

Appelez navigator.credentials.get() pour commencer à attendre l'authentification de l'utilisateur.

// To abort a WebAuthn call, instantiate an `AbortController`.
const abortController = new AbortController();

const publicKeyCredentialRequestOptions = {
  // Server generated challenge
  challenge: ****,
  // The same RP ID as used during registration
  rpId: 'example.com',
};

const credential = await navigator.credentials.get({
  publicKey: publicKeyCredentialRequestOptions,
  signal: abortController.signal,
  // Specify 'conditional' to activate conditional UI
  mediation: 'conditional'
});
  • rpId : un ID de RP est un domaine. Un site Web peut spécifier son domaine ou un suffixe enregistrable. Cette valeur doit correspondre au rp.id utilisé lors de la création de la clé d'accès.

N'oubliez pas de spécifier mediation: 'conditional' pour rendre la requête conditionnelle.

Envoyer les identifiants de clé publique renvoyés au serveur RP

Une fois que l'utilisateur a sélectionné un compte et autorisé à utiliser le verrouillage de l'écran de l'appareil, la promesse est résolue en renvoyant un objet PublicKeyCredential à l'interface RP.

Une promesse peut être refusée pour plusieurs raisons. Vous devez gérer les erreurs en conséquence, en fonction de la propriété name de l'objet Error:

  • NotAllowedError: l'utilisateur a annulé l'opération.
  • Autres exceptions: un événement inattendu s'est produit. Le navigateur affiche une boîte de dialogue d'erreur.

L'objet d'identification de clé publique contient les propriétés suivantes:

  • id : ID des identifiants de la clé d'accès authentifiée, encodé en base64url.
  • rawId : version ArrayBuffer de l'ID d'identification.
  • response.clientDataJSON : un ArrayBuffer de données client. Ce champ contient des informations telles que le défi et l'origine que le serveur de la RP doit vérifier.
  • response.authenticatorData : un ArrayBuffer de données d'authentificateur. Ce champ contient des informations telles que l'ID de la RP.
  • response.signature : objet ArrayBuffer de la signature. Cette valeur est le cœur de l'identifiant et doit être vérifiée sur le serveur.
  • response.userHandle : objet ArrayBuffer contenant l'ID utilisateur défini au moment de la création. Cette valeur peut être utilisée à la place de l'ID d'identification si le serveur doit choisir les valeurs d'ID qu'il utilise ou si le backend souhaite éviter de créer un index sur les ID d'identification.
  • authenticatorAttachment : renvoie platform lorsque cet identifiant provient de l'appareil local. Sinon, cross-platform, en particulier lorsque l'utilisateur a utilisé un téléphone pour se connecter. Si l'utilisateur doit se connecter à l'aide d'un téléphone, envisagez de l'inviter à créer une clé d'accès sur l'appareil local.
  • type: ce champ est toujours défini sur "public-key".

Si vous utilisez une bibliothèque pour gérer l'objet d'identification de clé publique sur le serveur de RP, nous vous recommandons d'envoyer l'objet entier au serveur après l'avoir partiellement encodé en base64url.

Vérifier la signature

Lorsque vous recevez les identifiants de clé publique sur le serveur, transmettez-les à la bibliothèque FIDO pour traiter l'objet.

Recherchez l'ID d'identifiant correspondant à l'aide de la propriété id (si vous devez déterminer le compte utilisateur, utilisez la propriété userHandle, qui correspond au user.id que vous avez spécifié lors de la création de l'identifiant). Vérifiez si l'identifiant signature de l'identifiant peut être validé avec la clé publique stockée. Pour ce faire, nous vous recommandons d'utiliser une bibliothèque côté serveur ou une solution au lieu d'écrire votre propre code. Vous trouverez des bibliothèques Open Source dans le dépôt GitHub vraiment génial-webauth.

Une fois l'identifiant validé avec une clé publique correspondante, connectez l'utilisateur.

Ressources