Inspector de WebAuthn y llaves de acceso online
Pega lo que devuelve navigator.credentials.create() o .get(): el JSON completo o un solo campo base64url. Cada parte se decodifica y se explica: clientDataJSON, los indicadores de los datos del autenticador bit a bit, el AAGUID, el ID de credencial, la clave pública COSE y la declaración de atestación. En los inicios de sesión, la firma ECDSA P-256 se verifica aquí mismo.
100 % local: todo se ejecuta en tu navegador y nada se envía a ningún servidor
La respuesta de navigator.credentials.create(): una llave de acceso nueva.
Decodificado
Aún no hay nada pegado
todo se decodifica localmenteEn la consola de tu navegador, ejecuta un registro o un inicio de sesión y copia el resultado. En Chrome y Safari, credential.toJSON() te da exactamente el JSON que espera este cuadro; el código más antiguo necesita los valores base64url de credential.response. O pulsa Cargar ejemplo para ver una respuesta real de una llave de acceso cuya firma se verifica.
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.