Start · Sprachen · JavaScript · Referenz · PublicKeyCredentialRequestOptions

PublicKeyCredentialRequestOptions

Schnittstelle

Konfigurationsobjekt für <code>navigator.credentials.get({ publicKey })</code>, mit dem eine WebAuthn-Anmeldung per Passkey oder Sicherheitsschlüssel angefordert wird.

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

Signatur

interface PublicKeyCredentialRequestOptions

Beschreibung

PublicKeyCredentialRequestOptions ist ein Dictionary (ein einfaches Objekt, kein Konstruktor) aus der Web Authentication API (WebAuthn). Es wird als Wert der Option publicKey an navigator.credentials.get() übergeben und beschreibt, wie sich ein Benutzer mit einem bereits registrierten Passkey, Sicherheitsschlüssel (z. B. YubiKey) oder Plattform-Authenticator (Touch ID, Windows Hello, Android) anmelden soll.

Das wichtigste Feld ist challenge: ein vom Server zufällig erzeugter, nur einmal gültiger Wert. Der Authenticator signiert ihn mit dem privaten Schlüssel. Der Server prüft die Signatur anschließend mit dem bei der Registrierung gespeicherten öffentlichen Schlüssel. So lassen sich Wiederholungsangriffe (Replay) verhindern. Mit allowCredentials legst du fest, welche Credentials erlaubt sind. Lässt du das Feld leer, bekommst du eine „nutzernamenlose“ Anmeldung mit auffindbaren Credentials (Discoverable Credentials, also Passkeys).

Normalerweise erzeugt der Server die Optionen (Challenge, rpId, erlaubte Credential-IDs) und schickt sie als JSON an den Client. Weil binäre Felder als ArrayBuffer bzw. TypedArray erwartet werden, musst du Base64URL-Strings vorher umwandeln. Moderne Browser bieten dafür PublicKeyCredential.parseRequestOptionsFromJSON().

Das Ergebnis von get() ist ein PublicKeyCredential, dessen response vom Typ AuthenticatorAssertionResponse ist. Diese Antwort (authenticatorData, clientDataJSON, signature, userHandle) schickst du zur Prüfung an den Server.

Parameter

Name Typ Default Beschreibung
$challenge Pflicht ArrayBuffer | TypedArray | DataView Vom Server erzeugter, kryptografisch zufälliger Wert (mind. 16 Byte empfohlen). Der Authenticator signiert ihn. Er darf nur einmal verwendet werden.
$rpId string Effektive Domain des aktuellen Ursprungs ID der Relying Party, also eine Domain wie example.com. Sie muss zur aktuellen Domain passen (gleich oder übergeordnet) und mit der bei der Registrierung verwendeten übereinstimmen.
$allowCredentials Array<{ type: 'public-key', id: BufferSource, transports?: string[] }> [] Liste der erlaubten Credentials. Ist sie leer, darf der Authenticator jedes auffindbare Credential (Passkey) für die rpId anbieten. transports (z. B. 'usb', 'nfc', 'ble', 'internal', 'hybrid') sind Hinweise für den Browser.
$userVerification 'required' | 'preferred' | 'discouraged' 'preferred' Legt fest, ob der Benutzer lokal verifiziert werden soll (PIN, Biometrie). Bei 'required' schlägt die Anmeldung fehl, wenn keine Verifikation möglich ist.
$timeout number Vom Browser abhängig Empfohlene maximale Wartezeit in Millisekunden. Der Browser darf diesen Wert anpassen.
$hints Array<'security-key' | 'client-device' | 'hybrid'> [] Hinweise an den Browser, welche Art von Authenticator in der Oberfläche bevorzugt werden soll (WebAuthn Level 3, noch nicht überall unterstützt).
$extensions object {} WebAuthn-Erweiterungen, z. B. appid (Migration von U2F), largeBlob oder prf. Die Ergebnisse liefert credential.getClientExtensionResults().

Rückgabewert

Typ
PublicKeyCredentialRequestOptions
Beschreibung
Ein reines Konfigurationsobjekt ohne eigenen Rückgabewert. navigator.credentials.get({ publicKey }) gibt ein Promise<PublicKeyCredential | null> zurück, dessen response eine AuthenticatorAssertionResponse ist.

Beispiele

Einfache Anmeldung mit bekannter Credential-ID

// Hilfsfunktion: Base64URL → Uint8Array
const b64urlToBytes = (s) => {
  const b64 = s.replace(/-/g, '+').replace(/_/g, '/').padEnd(Math.ceil(s.length / 4) * 4, '=');
  return Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
};

const login = async () => {
  // Server liefert Challenge und erlaubte Credential-IDs
  const res = await fetch('/webauthn/login/options', { method: 'POST' });
  const opts = await res.json();

  /** @type {PublicKeyCredentialRequestOptions} */
  const publicKey = {
    challenge: b64urlToBytes(opts.challenge),
    rpId: 'example.com',
    allowCredentials: opts.credentialIds.map((id) => ({
      type: 'public-key',
      id: b64urlToBytes(id),
      transports: ['internal', 'hybrid', 'usb']
    })),
    userVerification: 'preferred',
    timeout: 60000
  };

  const credential = await navigator.credentials.get({ publicKey });
  console.log(credential.type, credential.id);
  return credential;
};

login().catch((err) => console.error(err.name, err.message));
public-key AbC123...xyz

Passkey-Anmeldung ohne Benutzernamen und Senden an den Server

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

const passkeyLogin = async (challengeBytes) => {
  const credential = await navigator.credentials.get({
    publicKey: {
      challenge: challengeBytes,
      allowCredentials: [],          // leer = Passkey-Auswahl anzeigen
      userVerification: 'required'   // Biometrie/PIN erzwingen
    }
  });

  const { authenticatorData, clientDataJSON, signature, userHandle } = credential.response;

  const verify = await fetch('/webauthn/login/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      id: credential.id,
      authenticatorData: bytesToB64url(authenticatorData),
      clientDataJSON: bytesToB64url(clientDataJSON),
      signature: bytesToB64url(signature),
      userHandle: userHandle ? bytesToB64url(userHandle) : null
    })
  });
  console.log('Anmeldung ok:', verify.ok);
};

passkeyLogin(crypto.getRandomValues(new Uint8Array(32))); // nur Demo, Challenge gehört vom Server!
Anmeldung ok: true

JSON-Optionen parsen und Autofill (Conditional UI) nutzen

// HTML: <input type="text" autocomplete="username webauthn">
const startConditionalLogin = async () => {
  if (!window.PublicKeyCredential?.isConditionalMediationAvailable) return;
  if (!(await PublicKeyCredential.isConditionalMediationAvailable())) return;

  const json = await (await fetch('/webauthn/login/options')).json();

  // Wandelt Base64URL-Felder automatisch in ArrayBuffer um (sofern unterstützt)
  const publicKey = PublicKeyCredential.parseRequestOptionsFromJSON
    ? PublicKeyCredential.parseRequestOptionsFromJSON(json)
    : json; // sonst manuell konvertieren

  const abort = new AbortController();
  const credential = await navigator.credentials.get({
    publicKey,
    mediation: 'conditional', // Passkeys im Autofill-Menü anbieten
    signal: abort.signal
  });
  console.log('Gewählt:', credential.id);
  console.log(JSON.stringify(credential.toJSON?.() ?? {}).slice(0, 40));
};

startConditionalLogin();
Gewählt: AbC123...xyz