In diesem Leitfaden wird beschrieben, wie Sie eine zusätzliche Authentifizierung oder erneute Bestätigung für einen angemeldeten Nutzer implementieren, bevor er sensible Kontoänderungen vornimmt (z.B. Passwortaktualisierungen, Finanztransaktionen).
Delta-Flussarchitektur
Im Gegensatz zur regulären Authentifizierung werden bei der erneuten Authentifizierung mit Passkeys die Passkey-Dialogaufforderungen strikt auf die vorab registrierten Anmeldedaten des angemeldeten Nutzers beschränkt, um eine Kontovermischung oder Passkey-Spoofing während aktiver Sitzungen zu verhindern.
Serverseitig
Delta für die Generierung von Optionen
Erstellen Sie einen Endpunkt, der die Parameter für zulässige Anmeldedaten speziell für den aktiven, bekannten Nutzer füllt:
Anmeldedaten einschränken: Füllen Sie das Array mit den allowCredentials-Optionen mit bestimmten PublicKeyCredentialDescriptor-Einträgen, die alle registrierten Anmeldedaten-IDs für den angemeldeten Nutzer zuordnen. Wenn Sie dieses Feld leer lassen oder weglassen, wird auf auffindbare Anmeldedaten zurückgegriffen, was die Sitzungssicherheit beeinträchtigt.
// Node.js step-up options generation example
router.post("/api/reauth/options", enforceActiveSession, async (req, res) => {
const userPasskeys = await db.findCredentialsByUserId(req.user.id);
const options = {
challenge: serverGeneratedBase64UrlChallenge, // Random challenge stored in user session
rpId: "example.com",
// Enforce allowance strictly limited to the user's credentials list
allowCredentials: userPasskeys.map((cred) => ({
type: "public-key",
id: cred.id,
transports: cred.transports, // Speeds up resolution by indicating platform transports
})),
};
return res.json(options);
});
Delta des Bestätigungsendpunkts
Prüfen Sie die vom Client zurückgegebene Assertion:
Kontoinhaberschaft bestätigen: Der Bestätigungsendpunkt MUSS explizit prüfen, ob die vom Client zurückgegebene authentifizierte Anmeldedaten-ID einem gespeicherten Anmeldedatensatz zugeordnet ist, dessen zugehörige Nutzer-ID genau mit dem aktiven angemeldeten Nutzer (storedCredential.passkeyUserId === req.user.id) übereinstimmt. Wenn ein gültiger Passkey eines anderen Nutzers zurückgegeben wird, MUSS die Authentifizierung sofort abgelehnt werden.
Clientseitige Flussdeltas
Anwendungen wählen je nach Transaktions-UI zwischen zwei Schnittstellen für die erneute Authentifizierung:
A. Button Flow (No Input Fields)
Lösen Sie die erneute Authentifizierung aus, wenn ein Nutzer auf die Schaltfläche „Identität bestätigen“ oder „Transaktion fortsetzen“ klickt.
<button id="reauth-btn" data-testid="reauth-button">Confirm Transaction</button>
let reauthAbortController = new AbortController();
async function triggerButtonReauth() {
// Abort any background suggestion flows to avoid passkey prompt collisions
reauthAbortController.abort();
reauthAbortController = new AbortController();
const optionsResponse = await fetch("/api/reauth/options", {
method: "POST",
});
const optionsJSON = await optionsResponse.json();
const publicKey =
PublicKeyCredential.parseRequestOptionsFromJSON(optionsJSON);
try {
const credential = await navigator.credentials.get({
publicKey,
signal: reauthAbortController.signal,
});
if (credential) {
const encodedCredential = credential.toJSON();
const verifyResponse = await fetch("/api/reauth/verify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(encodedCredential),
});
if (verifyResponse.ok) {
showTransactionSuccessUI();
} else if (verifyResponse.status === 404 && PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encodedCredential.id
});
}
}
} catch (err) {
if (err.name === "NotAllowedError") {
console.log("User cancelled reauthentication.");
}
}
}
document
.getElementById("reauth-btn")
.addEventListener("click", triggerButtonReauth);
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';
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.parseRequestOptionsFromJSON und PublicKeyCredential.prototype.toJSON unterstützt.
import 'webauthn-polyfills';