Aller au contenu
ecdsa.com
WebAuthn navigator.credentials.create() with excludeCredentialsWebAuthn et clés d’accès

Message d’erreur

InvalidStateError: The user attempted to register an authenticator that contains one of the credentials already registered with the relying party.

Le texte ci-dessus est celui de Chromium ; les autres navigateurs le formulent différemment. Le nom de la DOMException, `InvalidStateError`, est la partie stable.

WebAuthn navigator.credentials.create() with excludeCredentials — DOMException InvalidStateError (Chromium)

Ce que cela signifie

L’enregistrement a été refusé, car l’authentificateur détient déjà l’un des identifiants que vous avez listés dans `excludeCredentials`. Les parties de confiance (relying parties, RP) envoient cette liste précisément pour empêcher qu’un même authentificateur soit enregistré deux fois pour un compte. C’est donc généralement le résultat voulu : l’utilisateur a déjà une clé d’accès fonctionnelle sur cet appareil. Les navigateurs ne le révèlent qu’après une interaction de l’utilisateur avec l’authentificateur.

Pourquoi cela se produit

Comment corriger l’erreur

  1. 1.

    Indiquer à l’utilisateur que tout est déjà configuré

    Traitez InvalidStateError comme « une clé d’accès existe déjà ici » et guidez l’utilisateur pour qu’il se connecte avec celle-ci.

    js
    try {
      const credential = await navigator.credentials.create({ publicKey: options });
      await saveCredential(credential);
    } catch (e) {
      if (e.name === "InvalidStateError") {
        showMessage("This device already has a passkey for your account. You can use it to sign in.");
      } else if (e.name !== "NotAllowedError") {
        throw e;
      }
    }
  2. 2.

    N’exclure que les identifiants de l’utilisateur actuel

    Construisez `excludeCredentials` à partir des ID d’identifiants stockés de l’utilisateur connecté, et utilisez un `user.id` aléatoire et stable pour chaque compte.

    js
    // Server: exclude only the CURRENT user's credentials (base64url ids from your database).
    const options = await generateRegistrationOptions({
      rpName: "Example",
      rpID,
      userName: user.email,
      userID: user.webauthnUserId,              // stable per user, never the email
      excludeCredentials: user.passkeys.map((p) => ({ id: p.credentialId, transports: p.transports })),
    });

Erreurs associées

Parcourir toute la base de données des erreurs de signature