本文へスキップ
ecdsa.com

WebAuthn・パスキーインスペクター

navigator.credentials.create() または .get() が返した内容を、JSON 全体のまま、または base64url のフィールド 1 つだけで貼り付けてください。すべての部分(clientDataJSON、ビット単位の認証器データのフラグ、AAGUID、認証情報 ID、COSE 公開鍵、アテステーションステートメント)をデコードして説明します。ログインの場合は、ECDSA P-256 の署名をこのページで検証します。

100% ローカル:すべてブラウザー内で処理され、どのサーバーにも何も送信されません

navigator.credentials.create() のレスポンス、つまり新しいパスキーです。

デコード結果

まだ何も貼り付けられていません

すべてローカルでデコードされます

ブラウザーのコンソールで登録またはログインを実行し、その結果をコピーしてください。Chrome と Safari では、credential.toJSON() を使うと、このボックスが想定するとおりの JSON が得られます。古いコードでは、credential.response から base64url の値を取り出す必要があります。または「サンプルを読み込む」を押すと、署名を検証できる本物のパスキーのレスポンスを確認できます。

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.