In diesem Leitfaden wird beschrieben, wie Sie einen Passkey für einen Nutzer sofort nach einer erfolgreichen passwortbasierten Anmeldung automatisch und im Hintergrund registrieren. So können Sie die Reibung minimieren und die Akzeptanz von Passkeys erhöhen.
Der richtige Trigger-Moment
Die automatische Passkey-Erstellung (auch als bedingte Erstellung oder unauffällige Aufforderung nach der Anmeldung bezeichnet) DARF nur unmittelbar nach einer erfolgreichen, vollständigen Anmeldung mit einem Passwort ausgelöst werden.
- Versuchen Sie nicht, eine bedingte Erstellung für passwortlose Abläufe (z.B. Magic Links, SMS-OTP oder Identitätsföderation) durchzuführen.
- Wenn eine Multi-Faktor-Authentifizierung erforderlich ist, MÜSSEN Sie warten, bis alle Faktoren erfolgreich abgeschlossen wurden, bevor Sie die bedingte Erstellung initiieren.
- Achten Sie darauf, dass eine gültige, authentifizierte Nutzersitzung aktiv ist, bevor Sie Anfragen an Erstellungsendpunkte senden.
Implementierungsschritte
1. Vorherige Autofill-Aktionen abbrechen
Wenn auf der Anmeldeseite das automatische Ausfüllen von Formularen (Conditional UI/Get) verwendet wird, muss der aktive Abruf der Anmeldedaten abgebrochen werden, um Browserkonflikte zu vermeiden.
- Rufe
abortController.abort()für dieAbortControllerauf, die an die ausstehendenavigator.credentials.get()-Anfrage zum automatischen Ausfüllen angehängt ist, bevor dunavigator.credentials.create()aufrufst.
2. Feature-Erkennung
Prüfen Sie mit conditionalCreate und PublicKeyCredential.getClientCapabilities(), ob die bedingte Erstellung verfügbar ist.
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate) {
// Conditional create is available
}
3. Passkey mit bedingter Erstellung erstellen
- Übergeben Sie
mediation: 'conditional'in dennavigator.credentials.create()-Optionen. Dadurch wird der Browser angewiesen, den Passkey-Erstellungsprozess im Hintergrund oder kontextbezogen zu verarbeiten, ohne aufdringliche modale Dialogfelder anzuzeigen. - Füllen Sie
excludeCredentialsmit den vorhandenen Passkey-Anmeldedaten-IDs des Nutzers, um die Registrierung doppelter Schlüssel zu vermeiden.
4. Stille Fehlerbehandlung
- Fügen Sie die Aufforderung zum Erstellen eines Passkeys (
navigator.credentials.create) in einen try/catch-Block ein. Sie MÜSSEN typische für Nutzer sichtbare Ausnahmen (InvalidStateError,NotAllowedError,AbortError) abfangen und ignorieren, ohne dem Nutzer eine Fehler-UI anzuzeigen.
5. Serverseitige Überprüfung der Nutzeranwesenheit
- Der Endpunkt für die serverseitige Überprüfung MUSS die Anforderung zur Nutzerpräsenz (
requireUserPresence: false) NUR dann lockern, wenn Anmeldedaten überprüft werden, die durch einen Trigger für die bedingte Erstellung erzeugt wurden. Die strenge Anwesenheitsbestätigung muss für standardmäßige explizite Erstellungen aktiv bleiben.
6. Fehlgeschlagene Serverüberprüfung ordnungsgemäß verarbeiten
- Wenn
navigator.credentials.create()erfolgreich ist, aber der Abruf der Serverbestätigung eine fehlerhafte Antwort zurückgibt (z.B. wenn die Signaturprüfung fehlschlägt), rufen SiePublicKeyCredential.signalUnknownCredential()auf, um zu verhindern, dass verwaiste Anmeldedaten im Passkey-Anbieter verbleiben.
Codebeispiel
// optionsFetch and registerVerifyFetch are app-defined server endpoint requests
import { optionsFetch, registerVerifyFetch } from './api.js';
async function triggerConditionalCreate(loginAbortController) {
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate !== true) {
return; // Platform does not support conditional creation
}
// 1. Abort any active autofill conditional-get controllers to clear the WebAuthn pipeline
loginAbortController.abort();
// 2. Fetch creation options signaling the backend that this is a conditional request
const creationOptionsJSON = await optionsFetch({ conditional: true });
const publicKey = PublicKeyCredential.parseCreationOptionsFromJSON(creationOptionsJSON);
let credential;
try {
// 3. Invoke silent credentials creation prompt
credential = await navigator.credentials.create({
publicKey,
mediation: 'conditional' // Silent background creation mediation
});
} catch (e) {
// 4. Silently swallow common WebAuthn browser exceptions
if (['InvalidStateError', 'NotAllowedError', 'AbortError'].includes(e.name)) {
return;
}
console.error('Unexpected conditional create error:', e);
return;
}
// 5. Server verification step using dedicated Try/Catch block
let encodedResponse = credential.toJSON();
try {
const response = await registerVerifyFetch(encodedResponse);
if (!response.ok) {
// If the server verification fails, clean up using Signal API
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encodedResponse.id
});
}
}
} catch (serverErr) {
console.error('Verification network failure:', serverErr);
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encodedResponse.id
});
}
}
}
Fallback-Strategien
Fallback für die Passkey-Funktionserkennung
Installieren Sie immer „webauthn-polyfills“ und importieren Sie es in den Kontext.
Solange PublicKeyCredential unterstützt wird, wird auch PublicKeyCredential.getClientCapabilities unterstützt.
import 'webauthn-polyfills';
Signal API-Synchronisierungs-Fallback
Die WebAuthn Signal API (webauthn-signals) ist eine progressive Optimierung, mit der Passwortmanager mit dem Status der Serveranmeldedaten synchronisiert werden.
- Fallback-Erfahrung: Über
if (PublicKeyCredential.signalUnknownCredential)eingeschränkt. Wenn sie nicht unterstützt wird, wird die Synchronisierung der Hintergrundüberprüfung ohne Browserausnahmen umgangen.
Einfacher Fallback für die JSON-Serialisierung
Installieren Sie immer „webauthn-polyfills“ und importieren Sie es in den Kontext.
Solange PublicKeyCredential unterstützt wird, werden auch PublicKeyCredential.parseCreationOptionsFromJSON und PublicKeyCredential.prototype.toJSON unterstützt.
import 'webauthn-polyfills';