Start · Sprachen · JavaScript · Referenz · PublicKeyCredential.response

PublicKeyCredential.response

Eigenschaft

Schreibgeschützte Eigenschaft mit der <code>AuthenticatorResponse</code> des Authenticators, also den kryptografischen Daten für Registrierung oder Anmeldung.

seit JavaScript Baseline: alle modernen Browser (WebAuthn Level 1, Kategorie: webapi

Signatur

PublicKeyCredential.response

Beschreibung

Die schreibgeschützte Eigenschaft response eines PublicKeyCredential enthält die Antwort des Authenticators (z. B. Sicherheitsschlüssel, Touch ID, Windows Hello oder ein Passkey auf dem Smartphone). Diese Daten schickt die Webanwendung an den Server. Dort werden sie geprüft, um einen neuen Schlüssel zu registrieren oder eine Anmeldung zu bestätigen.

Welcher Typ zurückkommt, hängt von der aufgerufenen Methode ab:

  • navigator.credentials.create() (Registrierung) liefert eine AuthenticatorAttestationResponse mit clientDataJSON, attestationObject sowie den Methoden getPublicKey(), getAuthenticatorData(), getPublicKeyAlgorithm() und getTransports().
  • navigator.credentials.get() (Anmeldung) liefert eine AuthenticatorAssertionResponse mit clientDataJSON, authenticatorData, signature und userHandle.

Fast alle Felder sind ArrayBuffer-Objekte. Für die Übertragung per JSON müssen sie deshalb erst kodiert werden, üblicherweise als Base64URL. Die eigentliche Prüfung (Challenge, Origin, Signatur, Zähler) muss immer auf dem Server passieren. Dem Client allein darf man hier nicht vertrauen.

Rückgabewert

Typ
AuthenticatorAttestationResponse | AuthenticatorAssertionResponse
Beschreibung
Ein AuthenticatorResponse-Objekt: bei create() eine AuthenticatorAttestationResponse, bei get() eine AuthenticatorAssertionResponse.

Beispiele

Registrierung: Attestation-Daten auslesen und an den Server senden

const toB64Url = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)))
  .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');

const registerPasskey = async (options) => {
  // options kommen vom Server (challenge, user.id als ArrayBuffer usw.)
  const credential = await navigator.credentials.create({ publicKey: options });
  const { response } = credential;

  console.log(response instanceof AuthenticatorAttestationResponse);

  await fetch('/webauthn/register', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      id: credential.id,
      rawId: toB64Url(credential.rawId),
      type: credential.type,
      response: {
        clientDataJSON: toB64Url(response.clientDataJSON),
        attestationObject: toB64Url(response.attestationObject),
        transports: response.getTransports?.() ?? []
      }
    })
  });
};
true

Anmeldung: Assertion-Daten übertragen

const toB64Url = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)))
  .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');

const login = async (challenge) => {
  const credential = await navigator.credentials.get({
    publicKey: { challenge, userVerification: 'preferred' }
  });
  const { response } = credential; // AuthenticatorAssertionResponse

  const payload = {
    id: credential.id,
    response: {
      clientDataJSON: toB64Url(response.clientDataJSON),
      authenticatorData: toB64Url(response.authenticatorData),
      signature: toB64Url(response.signature),
      userHandle: response.userHandle ? toB64Url(response.userHandle) : null
    }
  };
  const res = await fetch('/webauthn/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });
  return res.ok;
};

clientDataJSON zu Debugzwecken dekodieren

const inspectClientData = (credential) => {
  const json = new TextDecoder().decode(credential.response.clientDataJSON);
  const clientData = JSON.parse(json);
  console.log(clientData.type, clientData.origin);
  return clientData;
};
webauthn.get https://example.com

Moderne Abkürzung mit toJSON()

const credential = await navigator.credentials.get({ publicKey: options });
// Neuere Browser serialisieren response automatisch als Base64URL
const body = typeof credential.toJSON === 'function'
  ? JSON.stringify(credential)
  : null; // sonst manuell kodieren (siehe oben)
console.log(body !== null);
true

// Wichtig · Fallstricke

  • Nur Rohdaten: Die Werte in response sind ArrayBuffer. Ein direktes JSON.stringify(response) ergibt leere Objekte ({}). Man muss manuell kodieren oder PublicKeyCredential.prototype.toJSON() verwenden, das es erst in neueren Browsern gibt.
  • Serverseitige Prüfung ist Pflicht: Challenge, origin, RP-ID-Hash, Flags (User Present/Verified), Signatur und Signaturzähler müssen auf dem Server geprüft werden. Sonst lässt sich die Authentifizierung umgehen.
  • Typ prüfen: Welche Felder vorhanden sind, hängt vom Aufruf ab. signature gibt es nur bei der Assertion, attestationObject nur bei der Attestation. Im Zweifel mit instanceof unterscheiden.
  • userHandle kann null sein, wenn es kein auffindbares Credential (Passkey) ist.
  • Die Methoden getPublicKey(), getTransports() und getAuthenticatorData() kamen erst mit WebAuthn Level 2. In älteren Browsern vorher auf ihr Vorhandensein prüfen.
  • WebAuthn läuft nur in einem sicheren Kontext (HTTPS oder localhost). In iframes funktioniert es nur mit passender Permissions-Policy (publickey-credentials-get/-create).