Signatur
Beschreibung
CredentialsContainer.get() ist der zentrale Einstiegspunkt der Credential Management API und von WebAuthn. Die Methode wird über navigator.credentials.get() aufgerufen. Sie bittet den Browser, ein zur aktuellen Website passendes Anmelde-Credential herauszugeben. Je nach übergebenen Optionen kann das ein Passkey bzw. Sicherheitsschlüssel (PublicKeyCredential), ein gespeichertes Passwort (PasswordCredential), ein föderiertes Konto (FederatedCredential, IdentityCredential über FedCM) oder ein per SMS empfangener Einmalcode (OTPCredential) sein.
Am häufigsten wird die Methode heute für die passwortlose Anmeldung mit Passkeys genutzt. Der Server erzeugt eine zufällige Challenge, der Browser lässt den Nutzer per Biometrie, PIN oder Sicherheitsschlüssel bestätigen und gibt eine signierte AuthenticatorAssertionResponse zurück. Diese Antwort prüft der Server mit dem öffentlichen Schlüssel, den er bei der Registrierung mit navigator.credentials.create() gespeichert hat.
Über mediation legst du fest, wie viel Nutzerinteraktion nötig ist. Mit "silent" erfolgt die Anmeldung ohne Dialog, mit "optional" nur wenn nötig, mit "required" immer mit Dialog. "conditional" blendet Passkeys im Autofill-Menü eines Eingabefelds ein. Mit einem AbortSignal lässt sich eine laufende Anfrage abbrechen, zum Beispiel wenn der Nutzer die Seite wechselt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options | CredentialRequestOptions | {} | Objekt, das festlegt, welche Credential-Typen angefragt werden und wie. Mindestens einer der Typ-Schlüssel sollte gesetzt sein, sonst gibt es kein sinnvolles Ergebnis. |
| $options.publicKey | PublicKeyCredentialRequestOptions | WebAuthn-Optionen: challenge (ArrayBuffer/TypedArray, Pflicht), rpId, allowCredentials, userVerification ("required" | "preferred" | "discouraged"), timeout (ms), extensions, hints. |
|
| $options.password | boolean | false | Bei true kann ein gespeichertes PasswordCredential zurückgegeben werden (nur Chromium-Browser). |
| $options.federated | { providers: string[], protocols?: string[] } | Fragt ein FederatedCredential für die angegebenen Identitätsanbieter an (veraltet, nur Chromium). |
|
| $options.identity | IdentityCredentialRequestOptions | FedCM: { providers: [{ configURL, clientId, nonce }] }. Liefert ein IdentityCredential mit Token. |
|
| $options.otp | { transport: string[] } | WebOTP: z. B. { transport: ["sms"] }. Liest einen Einmalcode aus einer passenden SMS (Chrome Android). |
|
| $options.mediation | "silent" | "optional" | "conditional" | "required" | "optional" | Steuert, ob und wann der Browser den Nutzer um Bestätigung bittet. "conditional" aktiviert Passkey-Autofill. |
| $options.signal | AbortSignal | Ermöglicht den Abbruch der Anfrage. Das Promise wird dann mit einem AbortError abgelehnt. |
Rückgabewert
Credential-Untertyp erfüllt wird (PublicKeyCredential, PasswordCredential, FederatedCredential, IdentityCredential oder OTPCredential). Wird kein Credential gefunden oder bricht der Nutzer ab, kommt je nach Typ null zurück oder das Promise wird abgelehnt (z. B. NotAllowedError, AbortError, SecurityError).Beispiele
Anmeldung mit Passkey (WebAuthn)
// Hilfsfunktionen für Base64URL
const b64urlToBuf = (s) => Uint8Array.from(atob(s.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0));
const bufToB64url = (b) => btoa(String.fromCharCode(...new Uint8Array(b))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const loginWithPasskey = async () => {
// 1. Challenge vom Server holen
const { challenge } = await (await fetch('/webauthn/challenge')).json();
try {
// 2. Browser um signierte Assertion bitten
const cred = await navigator.credentials.get({
publicKey: {
challenge: b64urlToBuf(challenge),
rpId: location.hostname,
userVerification: 'preferred',
timeout: 60000
}
});
// 3. Antwort zur Prüfung an den Server senden
const res = await fetch('/webauthn/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: cred.id,
clientDataJSON: bufToB64url(cred.response.clientDataJSON),
authenticatorData: bufToB64url(cred.response.authenticatorData),
signature: bufToB64url(cred.response.signature),
userHandle: cred.response.userHandle ? bufToB64url(cred.response.userHandle) : null
})
});
console.log(res.ok ? 'Angemeldet' : 'Prüfung fehlgeschlagen');
} catch (err) {
if (err.name === 'NotAllowedError') console.log('Vom Nutzer abgebrochen oder Zeit abgelaufen');
else throw err;
}
};
document.querySelector('#login').addEventListener('click', loginWithPasskey);
Passkey-Autofill mit mediation: "conditional"
// HTML: <input name="username" autocomplete="username webauthn">
const controller = new AbortController();
const startConditionalUI = async () => {
if (!window.PublicKeyCredential?.isConditionalMediationAvailable) return;
if (!(await PublicKeyCredential.isConditionalMediationAvailable())) return;
const { challenge } = await (await fetch('/webauthn/challenge')).json();
const cred = await navigator.credentials.get({
mediation: 'conditional',
signal: controller.signal,
publicKey: {
challenge: Uint8Array.from(atob(challenge), c => c.charCodeAt(0)),
allowCredentials: [] // leer = auffindbare Passkeys anbieten
}
});
console.log('Passkey gewählt:', cred.id);
};
startConditionalUI().catch(err => {
if (err.name !== 'AbortError') console.error(err);
});
// Beim Wechsel zu einem anderen Login-Verfahren abbrechen
document.querySelector('#other-login').addEventListener('click', () => controller.abort());
Gespeichertes Passwort still abrufen (Chromium)
const autoSignIn = async () => {
if (!('PasswordCredential' in window)) return false;
const cred = await navigator.credentials.get({
password: true,
mediation: 'silent' // kein Dialog – nur wenn eindeutig möglich
});
if (!cred) {
console.log('Kein gespeichertes Passwort – Formular anzeigen');
return false;
}
const body = new URLSearchParams({ user: cred.id, pass: cred.password });
const res = await fetch('/login', { method: 'POST', body });
return res.ok;
};
autoSignIn().then(ok => console.log('Auto-Login:', ok));
Einmalcode per SMS einlesen (WebOTP)
// SMS-Ende muss lauten: @example.com #123456
const input = document.querySelector('input[autocomplete="one-time-code"]');
if ('OTPCredential' in window) {
const ac = new AbortController();
input.form.addEventListener('submit', () => ac.abort());
navigator.credentials.get({ otp: { transport: ['sms'] }, signal: ac.signal })
.then(otp => {
input.value = otp.code;
input.form.requestSubmit();
})
.catch(err => console.log('WebOTP:', err.name));
}