Start · Sprachen · JavaScript · Referenz · PublicKeyCredential.getClientExtensionResults()

PublicKeyCredential.getClientExtensionResults()

Methode

Gibt ein Objekt mit den Ergebnissen der clientseitig verarbeiteten WebAuthn-Erweiterungen zurück, die bei <code>create()</code> oder <code>get()</code> angefordert wurden.

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

Signatur

PublicKeyCredential.prototype.getClientExtensionResults()

Beschreibung

Die Methode getClientExtensionResults() eines PublicKeyCredential-Objekts liefert eine Zuordnung (Map-artiges Objekt) von Erweiterungskennungen zu ihren Ergebnissen. Welche Erweiterungen aktiv sind, legt die Anwendung über die Option extensions in navigator.credentials.create({ publicKey }) bzw. navigator.credentials.get({ publicKey }) fest.

Häufig verwendete Erweiterungen sind:

  • credProps: zeigt über rk an, ob ein auffindbarer Schlüssel (Passkey/Resident Key) angelegt wurde.
  • prf: leitet aus dem Authenticator geheime Werte ab, z. B. für Ende-zu-Ende-Verschlüsselung.
  • largeBlob: liest oder schreibt kleine Datenmengen, die zusammen mit dem Schlüssel gespeichert werden.
  • appid: Rückwärtskompatibilität mit alten FIDO-U2F-Registrierungen.
  • minPinLength, credentialProtectionPolicy u. a.

Wichtig: Diese Methode gibt nur die Client-Erweiterungsergebnisse zurück, also die Werte, die der Browser selbst erzeugt oder weiterreicht. Die Authenticator-Erweiterungsergebnisse stecken dagegen signiert in authenticatorData und müssen auf dem Server ausgewertet werden. Da die Client-Ergebnisse nicht signiert sind, dürfen sie auf dem Server nicht als vertrauenswürdig angesehen werden.

Rückgabewert

Typ
AuthenticationExtensionsClientOutputs (Object)
Beschreibung
Ein Objekt, dessen Schlüssel die Kennungen der verarbeiteten Erweiterungen sind (z. B. credProps, prf) und dessen Werte die jeweiligen Ergebnisse enthalten. Nicht unterstützte oder nicht angeforderte Erweiterungen fehlen; ohne Erweiterungen ist es ein leeres Objekt {}.

Beispiele

Prüfen, ob ein Passkey (Resident Key) erstellt wurde

const credential = await navigator.credentials.create({
  publicKey: {
    challenge: crypto.getRandomValues(new Uint8Array(32)),
    rp: { name: 'Beispiel GmbH', id: location.hostname },
    user: {
      id: new TextEncoder().encode('user-42'),
      name: 'anna@example.com',
      displayName: 'Anna'
    },
    pubKeyCredParams: [{ type: 'public-key', alg: -7 }, { type: 'public-key', alg: -257 }],
    authenticatorSelection: { residentKey: 'preferred' },
    extensions: { credProps: true }
  }
});

const results = credential.getClientExtensionResults();
console.log(results);

if (results.credProps?.rk) {
  console.log('Passkey gespeichert – Login ohne Benutzername möglich.');
} else {
  console.log('Kein auffindbarer Schlüssel – Benutzername weiterhin nötig.');
}
{ credProps: { rk: true } } Passkey gespeichert – Login ohne Benutzername möglich.

PRF-Erweiterung bei der Anmeldung auswerten

const salt = new TextEncoder().encode('verschluesselung-v1');

const assertion = await navigator.credentials.get({
  publicKey: {
    challenge: crypto.getRandomValues(new Uint8Array(32)),
    rpId: location.hostname,
    userVerification: 'required',
    extensions: { prf: { eval: { first: salt } } }
  }
});

const { prf } = assertion.getClientExtensionResults();

if (prf?.results?.first) {
  // ArrayBuffer mit 32 Byte – als Schlüsselmaterial nutzbar
  const key = await crypto.subtle.importKey(
    'raw', prf.results.first, 'HKDF', false, ['deriveKey']
  );
  console.log('PRF-Schlüssel abgeleitet:', key.type);
} else {
  console.log('Authenticator unterstützt PRF nicht.');
}
PRF-Schlüssel abgeleitet: secret

Ergebnisse zum Server senden

const sendToServer = async (credential) => {
  const toB64 = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)));

  const payload = {
    id: credential.id,
    type: credential.type,
    rawId: toB64(credential.rawId),
    response: {
      clientDataJSON: toB64(credential.response.clientDataJSON),
      authenticatorData: toB64(credential.response.authenticatorData),
      signature: toB64(credential.response.signature)
    },
    // Nur informativ – nicht signiert!
    clientExtensionResults: credential.getClientExtensionResults()
  };

  await fetch('/webauthn/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });
};

// Wichtig · Fallstricke

  • Nicht vertrauenswürdig: Client-Erweiterungsergebnisse sind nicht vom Authenticator signiert. Sicherheitsentscheidungen auf dem Server sollten sich auf die signierten Daten in authenticatorData stützen.
  • ArrayBuffer in JSON: Ergebnisse wie prf.results.first oder largeBlob.blob sind ArrayBuffer und werden von JSON.stringify() zu {}. Vorher nach Base64URL umwandeln oder PublicKeyCredential.prototype.toJSON() verwenden (sofern verfügbar).
  • Unterstützung variiert: Die Methode selbst ist in allen modernen Browsern vorhanden, die einzelnen Erweiterungen (z. B. prf, largeBlob) aber nicht überall. Fehlende Unterstützung äußert sich still durch fehlende Schlüssel – immer mit optionaler Verkettung (?.) prüfen.
  • Die Methode steht nur in einem sicheren Kontext (HTTPS oder localhost) zur Verfügung.
  • Jeder Aufruf liefert ein neues Objekt; Änderungen daran wirken sich nicht auf das Credential aus.