Aller au contenu
ecdsa.com

WebAuthn / Passkey Inspector — inspecteur WebAuthn et de clés d’accès

Collez ce que navigator.credentials.create() ou .get() vous a renvoyé : le JSON complet ou un seul champ base64url. Chaque partie est décodée et expliquée : clientDataJSON, les indicateurs des données de l’authentificateur bit par bit, l’AAGUID, l’ID d’identifiant, la clé publique COSE et la déclaration d’attestation. Pour les connexions, la signature ECDSA P-256 est vérifiée directement ici.

100 % local : tout s’exécute dans votre navigateur, rien n’est envoyé à aucun serveur

La réponse de navigator.credentials.create() : une nouvelle clé d’accès.

Décodé

Rien n’a encore été collé

tout est décodé localement

Dans la console de votre navigateur, lancez un enregistrement ou une connexion et copiez le résultat. Dans Chrome et Safari, credential.toJSON() fournit exactement le JSON qu’attend cette zone ; avec du code plus ancien, il faut les valeurs base64url de credential.response. Vous pouvez aussi appuyer sur Charger un exemple pour voir une vraie réponse de clé d’accès dont la signature se vérifie.

How it works

A passkey is an ECDSA key pair — almost always on the P-256 curve — created by your phone, laptop or security key. The private half never leaves that device. Registration hands your server the public half; every later login is a signature made with the private half over data your server chose. There is no shared secret to steal, and the browser refuses to sign for a site the credential was not created on, which is what makes passkeys phishing-resistant.

The browser returns two or three base64url blobs. clientDataJSON is plain JSON describing what the browser saw: the ceremony type, your challenge, and the real origin. authenticatorData is a packed binary record: 32 bytes of SHA-256(RP ID), one flags byte, a 4-byte counter, and — during registration — the AAGUID, the credential ID and the new public key as a CBOR-encoded COSE_Key. During registration that record is wrapped in an attestationObject, a CBOR map that adds the authenticator's optional statement about its own make and model.

Verifying a login is one line of maths: verify(signature, SHA-256(authenticatorData ‖ SHA-256(clientDataJSON)), publicKey). Note what is not in there — the challenge and the origin are only covered because they sit inside clientDataJSON, so a valid signature is necessary but never sufficient: your server still has to read those fields and compare them with what it expects. WebAuthn signatures are ASN.1 DER, not the raw r‖s format JWTs use, which is a common source of "valid signature that will not verify".

The same page checks the attestation statement of a registration in every format the WebAuthn registry defines — packed, tpm, android-key, android-safetynet, fido-u2f, apple, none and compound — and assertion signatures with every COSE algorithm a credential may carry: ES256, ES384, ES512, EdDSA, RS256, PS256 and their relatives. A valid attestation proves that whoever holds the attestation key signed this registration; whether that key belongs to hardware you trust is a separate decision, made by chaining its certificates to a root you accept — normally one the FIDO Metadata Service publishes, which the AAGUID Lookup reads for you.

This page does all of it in your browser: the CBOR decoder and the WebAuthn parsers are written from scratch, ECDSA and EdDSA signatures are checked with the audited @noble/curves library, and RSA signatures with a few dozen lines of RFC 8017 arithmetic. Nothing you paste is uploaded, logged or stored — which matters, because a real response identifies a real credential of a real user.