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 tenant compte des utilisateurs de mots de passe existants.

Les clés d'accès remplacent les mots de passe et rendent les comptes utilisateur plus sûrs, plus simples et plus faciles à utiliser. Toutefois, la transition de l'authentification par mot de passe à l'authentification basée sur une clé 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 aider à créer une expérience unifiée.

Pourquoi utiliser le remplissage automatique de formulaire 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.

Idéalement, il n'y aurait pas d'utilisateurs 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 alors choisir un compte et déverrouiller l'écran pour vérifier et se connecter.

Cependant, la transition de l'authentification par mot de passe à l'authentification par clé d'accès peut s'avérer difficile. Lorsque les utilisateurs passeront aux clés d'accès, certains devront continuer à utiliser des mots de passe et des sites Web pour s'adapter aux deux types d'utilisateurs. Les utilisateurs eux-mêmes ne doivent pas se souvenir des sites sur lesquels ils sont passés aux clés d'accès. Par conséquent, demander aux utilisateurs de sélectionner la méthode à utiliser dès le départ constituerait une mauvaise expérience utilisateur.

Les clés d'accès sont également une nouvelle technologie. Pour les sites Web, il peut être difficile de les expliquer et de s'assurer que les utilisateurs se sentent à l'aise avec leur utilisation. 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 à la fois 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 une UI conditionnelle et 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, ainsi que des suggestions de saisie automatique de mot 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 avec l'avantage supplémentaire de sécurité 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 :

  • Backend: votre serveur backend contenant la base de données des comptes, qui stocke la clé publique et d'autres métadonnées associées à la clé d'accès.
  • Interface: interface qui communique avec le navigateur et envoie des requêtes de récupération au backend.
  • Navigateur: le 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. Elle peut se trouver sur le même appareil que le navigateur (par exemple, lorsque vous utilisez Windows Hello) ou sur un autre appareil, comme un téléphone.
Schéma de l'authentification par clé d'accès
  1. Dès qu'un utilisateur accède à l'interface, il demande au backend une question d'authentification pour s'authentifier avec une clé d'accès et appelle navigator.credentials.get() pour initier 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 des mots de passe, y compris 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 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é.

Prérequis

L'interface utilisateur WebAuthn conditionnelle est disponible publiquement dans Safari sur iOS 16, iPadOS 16 et macOS Ventura. Il est également disponible sur Chrome sous 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 WebAuthn get conditionnel pour indiquer que les 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'interface utilisateur et reste en attente jusqu'à ce que l'utilisateur sélectionne un compte avec lequel se connecter dans les suggestions de saisie automatique. Si l'utilisateur choisit une clé d'accès, le navigateur résout la promesse avec un identifiant au lieu de remplir le formulaire de connexion. Il incombe alors à la page de connecter l'utilisateur.

Annoter le champ de saisie du formulaire

Ajoutez un attribut autocomplete dans le champ input du nom d'utilisateur, si nécessaire. Ajoutez username et webauthn en tant que jetons pour lui permettre de suggérer des clés d'accès.

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

Détection de fonctionnalités

Avant d'appeler un appel d'API WebAuthn conditionnel, vérifiez si:

  • Le navigateur est compatible avec WebAuthn.
  • Le navigateur est compatible avec l'interface utilisateur 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 auprès du serveur de la RP

Récupérez une question d'authentification auprès du serveur RP qui est nécessaire 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 empêcher les attaques par rejeu. Veillez à générer une nouvelle question d'authentification à chaque tentative de connexion et à l'ignorer après un certain délai ou si la validation d'une tentative de connexion échoue. Considérez-le 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 vérification de l'utilisateur. Définissez cette valeur sur "preferred" ou omettez la propriété.

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

Appelez navigator.credentials.get() pour 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 et 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 consenti à l'aide du verrouillage de l'écran de l'appareil, la promesse est résolue en renvoyant un objet PublicKeyCredential à l'interface de la RP.

Une promesse peut être rejeté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'utilisateur.

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

  • id : ID de la clé d'accès authentifiée, encodé en base64url.
  • rawId : version ArrayBuffer de l'ID d'identification.
  • response.clientDataJSON : ArrayBuffer de données client. Ce champ contient des informations telles que la question d'authentification et l'origine que le serveur RP devra vérifier.
  • response.authenticatorData : ArrayBuffer de données d'authentification. Ce champ contient des informations telles que l'ID du tiers assujetti à des restrictions.
  • response.signature : ArrayBuffer de la signature. Cette valeur est l'élément central de l'identifiant et doit être validée sur le serveur.
  • response.userHandle : 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 qu'il utilise ou si le backend souhaite éviter de créer un index sur les identifiants.
  • authenticatorAttachment : renvoie platform lorsque cet identifiant provient de l'appareil local. Sinon, cross-platform, en particulier lorsque l'utilisateur s'est connecté avec un téléphone. Si l'utilisateur a besoin de se connecter à l'aide d'un téléphone, invitez-le à 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'identifiants de clé publique sur le serveur RP, nous vous recommandons d'envoyer l'objet entier au serveur après l'avoir encodé partiellement 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 à l'identifiant user.id que vous avez spécifié lors de la création de l'identifiant). Vérifiez si le signature des identifiants peut être vérifié avec la clé publique stockée. Pour ce faire, nous vous recommandons d'utiliser une bibliothèque ou une solution côté serveur au lieu d'écrire votre propre code. Vous trouverez des bibliothèques Open Source dans le dépôt GitHub super-webauth.

Une fois les identifiants validés à l'aide d'une clé publique correspondante, connectez l'utilisateur.

Ressources