SimpleWebAuthn répartit WebAuthn entre deux paquets : @simplewebauthn/browser encapsule navigator.credentials, et @simplewebauthn/server génère les options qu’envoie une partie de confiance (relying party, RP) et vérifie ce qui revient (formats d’attestation, clés COSE, compteurs et signatures). Les essais ont piloté le paquet serveur avec un authentificateur logiciel produisant du JSON d’enregistrement et d’assertion standard, les mêmes octets que pour les pages Python, Go et Java.
Le bug d’intégration le plus courant est un décalage entre ce que demandent les options et ce qu’exige la vérification. generateRegistrationOptions() utilise par défaut userVerification: "preferred", mais les deux vérificateurs utilisent par défaut requireUserVerification: true : une assertion provenant d’un authentificateur qui n’avait prouvé que la présence de l’utilisateur (une clé de sécurité sans PIN) a été refusée avec User verification required, but user could not be verified. Tranchez une fois pour toutes et faites en sorte que les deux côtés disent la même chose, comme le fait l’exemple.
Les signatures d’assertion ES256 doivent être en ASN.1 DER, comme l’exige la spécification WebAuthn. Une signature r‖s brute de 64 octets est quand même transmise à l’analyseur ASN.1 et échoue avec un message qui dépend des octets de la signature et ne mentionne jamais l’encodage ; sur 60 identifiants neufs, les plus fréquents étaient Too big integer, End of input reached before message was fully decoded et Data does not match to ECDSASigValue ASN1 schema. Les authentificateurs et les fournisseurs de clés d’accès produisent du DER : des signatures brutes trahissent donc en général un client écrit à la main ou un banc de test qui a appelé directement le sign() de WebCrypto. Convertissez-les avec le convertisseur DER ⇄ brut. Une signature DER high-S a été vérifiée.
Un compteur de signatures inférieur à la valeur enregistrée est une erreur, pas un avertissement : la vérification a levé Response counter value 3 was lower than expected 5, et un compteur à 0 après un 5 enregistré a échoué de la même façon. Seul un identifiant qui a toujours renvoyé 0, comme le font les clés d’accès synchronisées, passe avec 0. Enregistrez le compteur reçu et décidez vous-même si une régression bloque l’identifiant ou déclenche seulement une alerte. La version 14 place ML-DSA-44 (COSE -48) en tête des pubKeyCredParams par défaut, avant Ed25519 (-8), ES256 (-7) et RS256 (-257), et l’identifiant Ed25519 a été vérifié de bout en bout.
Décodez ce qu’un navigateur a réellement envoyé avec l’inspecteur WebAuthn, essayez les parcours sans véritable authentificateur dans le bac à sable des clés d’accès, et identifiez les modèles d’authentificateurs par leur AAGUID avec la recherche d’AAGUID.