Présentation détaillée des identifiants

Bien que les identifiants FIDO tels que les clés d'accès visent à remplacer les mots de passe, la plupart d'entre eux peuvent également éviter à l'utilisateur de saisir un nom d'utilisateur. Cela permet aux utilisateurs de s'authentifier en sélectionnant un compte dans une liste de clés d'accès dont ils disposent pour le site Web actuel.

Les anciennes versions des clés de sécurité ont été conçues comme des méthodes d'authentification en deux étapes. Elles nécessitaient l'identification des identifiants potentiels, nécessitant la saisie d'un nom d'utilisateur. Les identifiants qu'une clé de sécurité peut trouver sans connaître leur ID sont appelés "identifiants détectables". La plupart des identifiants FIDO créés aujourd'hui sont visibles, en particulier les clés d'accès stockées dans un gestionnaire de mots de passe ou sur une clé de sécurité moderne.

Pour vous assurer que vos identifiants sont visibles, spécifiez residentKey et requireResidentKey lorsque la clé d'accès est créée.

Les parties de confiance peuvent utiliser les identifiants détectables en omettant allowCredentials lors de l'authentification par clé d'accès. Dans ce cas, le navigateur ou le système présente à l'utilisateur une liste des clés d'accès disponibles, identifiées par la propriété user.name définie au moment de la création. Si l'utilisateur en sélectionne une, la valeur user.id est incluse dans la signature obtenue. Le serveur peut ensuite utiliser cet ID ou l'ID d'identification renvoyé pour rechercher le compte au lieu d'un nom d'utilisateur saisi.

Les interfaces utilisateur du sélecteur de compte, comme celles mentionnées précédemment, n'affichent jamais d'identifiants non visibles.

requireResidentKey et residentKey

Pour créer des identifiants détectables, spécifiez authenticatorSelection.residentKey et authenticatorSelection.requireResidentKey sur navigator.credentials.create() avec les valeurs indiquées ci-dessous.

async function register () {
  // ...

  const publicKeyCredentialCreationOptions = {
    // ...
    authenticatorSelection: {
      authenticatorAttachment: 'platform',
      residentKey: 'required',
      requireResidentKey: true,
    }
  };

  const credential = await navigator.credentials.create({
    publicKey: publicKeyCredentialCreationOptions
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;

  // ...
}

residentKey:

  • 'required': un identifiant visible doit être créé. Si elle ne peut pas être créée, NotSupportedError est renvoyé.
  • 'preferred': le tiers assujetti à des restrictions préfère créer des identifiants détectables, mais accepte ceux qui ne le sont pas.
  • 'discouraged': le tiers assujetti à des restrictions préfère créer des identifiants non visibles, mais accepte les identifiants détectables.

requireResidentKey:

  • Cette propriété est conservée pour assurer la rétrocompatibilité à partir de WebAuthn niveau 1, une ancienne version de la spécification. Définissez cette valeur sur true si residentKey est définie sur 'required'. Sinon, définissez-la sur false.

allowCredentials

Les tiers assujettis à des restrictions peuvent utiliser allowCredentials sur navigator.credentials.get() pour contrôler l'expérience d'authentification par clé d'accès. Il existe généralement trois types d'expériences d'authentification par clé d'accès:

Grâce aux identifiants détectables, les tiers assujettis à des restrictions peuvent afficher un sélecteur de compte modal permettant à l'utilisateur de choisir le compte avec lequel se connecter, suivi de la validation de l'utilisateur. Cela convient au processus d'authentification par clé d'accès lancé en appuyant sur un bouton dédié.

Pour bénéficier de cette expérience utilisateur, omettez ou transmettez un tableau vide au paramètre allowCredentials dans navigator.credentials.get().

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

Afficher le remplissage automatique des formulaires de clés d'accès

Le sélecteur de compte modal décrit ci-dessus fonctionne bien si la plupart des utilisateurs utilisent des clés d'accès et qu'elles sont disponibles sur l'appareil local. Pour un utilisateur qui ne possède pas de clé d'accès locale, la boîte de dialogue modale s'affiche toujours et propose à l'utilisateur de présenter une clé d'accès depuis un autre appareil. Lors de la transition de vos utilisateurs vers des clés d'accès, vous pouvez éviter cette UI pour les utilisateurs qui n'en ont pas configuré une.

Au lieu de cela, la sélection d'une clé d'accès peut être intégrée dans des invites de saisie automatique pour les champs d'un formulaire de connexion classique, aux côtés des noms d'utilisateur et des mots de passe enregistrés. Ainsi, un utilisateur disposant de clés d'accès peut "remplir" le formulaire de connexion en sélectionnant sa clé d'accès, les utilisateurs ayant des paires nom d'utilisateur/mot de passe enregistrées peuvent les sélectionner, et les utilisateurs qui n'en disposent pas peuvent toujours saisir leur nom d'utilisateur et leur mot de passe.

Cette expérience utilisateur est idéale lorsque le tiers assujetti à des restrictions fait l'objet d'une migration avec une utilisation mixte de mots de passe et de clés d'accès.

Pour proposer cette expérience utilisateur, en plus de transmettre un tableau vide à la propriété allowCredentials ou d'omettre le paramètre, spécifiez mediation: 'conditional' sur navigator.credentials.get() et annotez un champ de saisie HTML username avec autocomplete="username webauthn" ou un champ de saisie password avec autocomplete="password webauthn".

L'appel de navigator.credentials.get() n'entraîne pas l'affichage d'UI, mais si l'utilisateur sélectionne le champ de saisie annoté, toutes les clés d'accès disponibles seront incluses dans les options de saisie automatique. Si l'utilisateur en sélectionne une, il devra suivre la procédure habituelle de validation du déverrouillage de l'appareil. Ce n'est qu'alors que la promesse renvoyée par .get() se résoudra et que le résultat s'affichera. Si l'utilisateur ne sélectionne pas de clé d'accès, la promesse ne se résout jamais.

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const cred = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal,
    // Specify 'conditional' to activate conditional UI
    mediation: 'conditional'
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}
<input type="text" name="username" autocomplete="username webauthn" ...>

Pour découvrir comment créer cette expérience utilisateur, consultez Se connecter avec une clé d'accès via le remplissage automatique de formulaire et l'atelier de programmation Implémenter des clés d'accès avec le remplissage automatique de formulaire dans une application Web.

Réauthentification

Dans certains cas, par exemple lors de l'utilisation de clés d'accès pour la réauthentification, l'identifiant de l'utilisateur est déjà connu. Dans ce cas, nous aimerions utiliser une clé d'accès sans que le navigateur ni le système d'exploitation n'affichent une forme de sélecteur de compte. Pour ce faire, transmettez une liste d'ID d'identifiants dans le paramètre allowCredentials.

Dans ce cas, si l'un des identifiants nommés est disponible localement, l'utilisateur est immédiatement invité à déverrouiller l'appareil. Si ce n'est pas le cas, l'utilisateur est invité à présenter un autre appareil (un téléphone ou une clé de sécurité) contenant un identifiant valide.

Pour proposer cette expérience utilisateur, fournissez la liste des identifiants de l'utilisateur qui se connecte. Le tiers assujetti à des restrictions doit pouvoir les interroger, car l'utilisateur est déjà connu. Fournissez les ID d'identification en tant qu'objets PublicKeyCredentialDescriptor dans la propriété allowCredentials de navigator.credentials.get().

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // Provide a list of PublicKeyCredentialDescriptors:
    allowCredentials: [{
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, {
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, ...]
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

Un objet PublicKeyCredentialDescriptor comprend les éléments suivants:

  • id: ID de l'identifiant de clé publique obtenu par le tiers assujetti à des restrictions lors de l'enregistrement de la clé d'accès.
  • type: ce champ contient généralement 'public-key'.
  • transports: indice des transports compatibles avec l'appareil détenant cet identifiant, utilisé par les navigateurs pour optimiser l'interface utilisateur qui demande à l'utilisateur de présenter un appareil externe. Si elle est fournie, cette liste doit contenir le résultat de l'appel de getTransports() lors de l'enregistrement de chaque identifiant.

Résumé

La visibilité des identifiants rend l'expérience de connexion par clé d'accès beaucoup plus conviviale, car les utilisateurs n'ont pas à saisir de nom d'utilisateur. En combinant residentKey, requireResidentKey et allowCredentials, les tiers assujettis à des restrictions peuvent proposer des expériences de connexion qui:

  • Afficher un sélecteur de compte en mode modal
  • Affichez le remplissage automatique des formulaires de clés d'accès.
  • Réauthentification.

Utilisez les identifiants détectables à bon escient. Vous pouvez ainsi concevoir des expériences sophistiquées de connexion par clé d'accès que les utilisateurs trouveront fluides et seront plus susceptibles d'interagir avec elles.