1. Hinweis
Die Verwendung von Passkeys anstelle von Passwörtern ist eine hervorragende Möglichkeit für Websites, die Nutzerkonten sicherer, einfacher und benutzerfreundlicher zu gestalten. Mit einem Passkey kann sich ein Nutzer auf einer Website oder in einer App anmelden, indem er die Displaysperre des Geräts verwendet, z. B. einen Fingerabdruck, die Gesichtserkennung oder eine Geräte-PIN. Ein Passkey muss erstellt, einem Nutzerkonto zugewiesen und sein öffentlicher Schlüssel auf einem Server gespeichert werden, bevor sich ein Nutzer damit anmelden kann.
In diesem Codelab wandeln Sie eine einfache formularbasierte Anmeldung mit Nutzername und Passwort in eine Anmeldung um, die Passkeys unterstützt und Folgendes umfasst:
- Eine Schaltfläche, mit der nach der Anmeldung des Nutzers ein Passkey erstellt wird.
- Eine Benutzeroberfläche, auf der eine Liste der registrierten Passkeys angezeigt wird.
- Das vorhandene Anmeldeformular, mit dem sich Nutzer mit einem registrierten Passkey über die Autofill-Funktion anmelden können.
Vorbereitung
- Grundlegende Kenntnisse von JavaScript
- Grundlegendes Verständnis der Web Authentication API (WebAuthn)
Lerninhalte
- So erstellen Sie einen Passkey.
- Nutzer mit einem Passkey authentifizieren
- So kann in einem Formular ein Passkey als Anmeldeoption vorgeschlagen werden.
2. Einrichten
In diesem Codelab klonen Sie eine unvollständige Demo-App von GitHub und schließen dann die Implementierung der Passkey-Unterstützung ab.
Projekt klonen
- Öffnen Sie das Projekt auf GitHub.
- Klonen Sie das Projekt oder laden Sie es herunter.

Projekt ausführen
- Öffnen Sie ein Terminal und verwenden Sie
cd start, um das Verzeichnis zu wechseln. - Führen Sie
npm installaus, um die Projektabhängigkeiten zu installieren. - Erstellen Sie das Projekt mit
npm run build && IS_LOCAL=1 npm run startund führen Sie es aus. - Öffnen Sie in Ihrem Browser http://localhost:8080/.
Ausgangszustand der Website prüfen
- Geben Sie auf der Website einen zufälligen Nutzernamen ein und klicken Sie auf Weiter.
- Geben Sie ein beliebiges Passwort ein und klicken Sie auf Anmelden. Das Passwort wird ignoriert, Sie werden aber trotzdem authentifiziert und zur Startseite weitergeleitet.
- Wenn Sie Ihren Anzeigenamen ändern möchten, können Sie das tun. Das ist alles, was Sie im Ausgangszustand tun können.
- Klicken Sie auf Abmelden.
In diesem Status müssen Nutzer bei jeder Anmeldung ein Passwort eingeben. Sie fügen diesem Formular Unterstützung für Passkeys hinzu, damit sich Nutzer mit der Displaysperre des Geräts anmelden können.
Weitere Informationen zur Funktionsweise von Passkeys finden Sie unter Wie funktionieren Passkeys?.
3. Möglichkeit zum Erstellen eines Passkeys hinzufügen
Damit sich Nutzer mit einem Passkey authentifizieren können, müssen Sie ihnen die Möglichkeit geben, einen Passkey zu erstellen und zu registrieren und den öffentlichen Schlüssel auf dem Server zu speichern.

Sie möchten die Erstellung eines Passkeys zulassen, nachdem sich der Nutzer mit einem Passwort angemeldet hat, und eine Benutzeroberfläche hinzufügen, über die Nutzer einen Passkey erstellen und eine Liste aller registrierten Passkeys auf der Seite /home aufrufen können. Im nächsten Abschnitt erstellen Sie eine Funktion, mit der ein Passkey erstellt und registriert wird.
Funktion registerCredential() erstellen
- Öffnen Sie das Verzeichnis
startin einem Code-Editor Ihrer Wahl. - Rufen Sie die Datei
public/client.jsauf und scrollen Sie zum Ende. - Fügen Sie nach dem entsprechenden Kommentar die folgende
registerCredential()-Funktion hinzu:
public/client.js
// TODO: Add an ability to create a passkey: Create the registerCredential() function.
export async function registerCredential() {
// TODO: Add an ability to create a passkey: Obtain the challenge and other options from the server endpoint.
// TODO: Add an ability to create a passkey: Create a credential.
// TODO: Add an ability to create a passkey: Register the credential to the server endpoint.
};
Diese Funktion erstellt und registriert einen Passkey auf dem Server.
Herausforderung und andere Optionen vom Serverendpunkt abrufen
Bevor ein Passkey erstellt wird, müssen Sie Parameter anfordern, die Sie vom Server an WebAuthn übergeben, einschließlich einer Challenge. WebAuthn ist eine Browser-API, mit der ein Nutzer einen Passkey erstellen und sich mit dem Passkey authentifizieren kann. Glücklicherweise haben Sie in diesem Codelab bereits einen Serverendpunkt, der mit solchen Parametern antwortet.
- Fügen Sie den folgenden Code nach dem entsprechenden Kommentar in den Textkörper der Funktion
registerCredential()ein, um die Challenge und andere Optionen vom Serverendpunkt abzurufen:
public/client.js
// TODO: Add an ability to create a passkey: Obtain the challenge and other options from the server endpoint.
const _options = await _fetch('/auth/registerRequest');
Das folgende Code-Snippet enthält Beispieloptionen, die Sie vom Server erhalten:
{
challenge: *****,
rp: {
id: "example.com",
},
user: {
id: *****,
name: "john78",
displayName: "John",
},
pubKeyCredParams: [{
alg: -7, type: "public-key"
},{
alg: -257, type: "public-key"
}],
excludeCredentials: [{
id: *****,
type: 'public-key',
transports: ['internal', 'hybrid'],
}],
authenticatorSelection: {
authenticatorAttachment: "platform",
requireResidentKey: true,
}
}
Das Protokoll zwischen einem Server und einem Client ist nicht Teil der WebAuthn-Spezifikation. Der Server dieses Codelabs ist jedoch so konzipiert, dass er ein JSON zurückgibt, das dem PublicKeyCredentialCreationOptions-Dictionary, das an die WebAuthn-navigator.credentials.create()-API übergeben wird, so ähnlich wie möglich ist.
Die folgende Tabelle ist nicht vollständig, enthält aber die wichtigen Parameter im PublicKeyCredentialCreationOptions-Dictionary:
Parameter | Textzeilen |
Eine vom Server generierte Challenge in einem | |
Die eindeutige ID eines Nutzers. Dieser Wert muss ein | |
Dieses Feld sollte eine eindeutige Kennung für das Konto enthalten, die für den Nutzer erkennbar ist, z. B. seine E-Mail-Adresse oder seinen Nutzernamen. Sie wird in der Kontoauswahl angezeigt. Wenn Sie einen Nutzernamen verwenden, verwenden Sie denselben Wert wie bei der Passwortauthentifizierung. | |
Dieses Feld ist ein optionaler, nutzerfreundlicher Name für das Konto. Er muss nicht eindeutig sein und kann der vom Nutzer gewählte Name sein. Wenn Ihre Website keinen geeigneten Wert für dieses Feld hat, übergeben Sie einen leeren String. Je nach Browser wird dies möglicherweise in der Kontoauswahl angezeigt. | |
Eine Relying Party-ID (RP) ist eine Domain. Eine Website kann entweder ihre Domain oder ein registrierbares Suffix angeben. Wenn der Ursprung eines RP beispielsweise https://login.beispiel.de:1337 ist, kann die RP-ID entweder | |
In diesem Feld werden die vom RP unterstützten Algorithmen für öffentliche Schlüssel angegeben. Wir empfehlen, den Wert auf | |
Stellt eine Liste der bereits registrierten Anmeldedaten-IDs bereit, um eine doppelte Registrierung desselben Geräts zu verhindern. Falls angegeben, sollte das | |
Legen Sie einen | |
Auf einen booleschen | |
Legen Sie den Wert auf |
Anmeldedaten erstellen
- Konvertieren Sie im Hauptteil der Funktion
registerCredential()nach dem entsprechenden Kommentar einige mit Base64URL codierte Parameter zurück in Binärdaten, insbesondere die Stringsuser.idundchallengesowie Instanzen des Stringsid, die im ArrayexcludeCredentialsenthalten sind. Dazu können Sie die FunktionPublicKeyCredential.parseCreationOptionsFromJSON()verwenden:
public/client.js
// TODO: Add an ability to create a passkey: Create a credential.
// Deserialize and decode the `PublicKeyCredential.parseCreationOptionsFromJSON()`.
const options = PublicKeyCredential.parseCreationOptionsFromJSON(_options);
- Legen Sie in der nächsten Zeile
authenticatorSelection.authenticatorAttachmentauf"platform"undauthenticatorSelection.requireResidentKeyauftruefest. Dadurch kann nur ein Plattform-Authenticator (das Gerät selbst) mit einer Funktion für erkennbare Anmeldedaten verwendet werden.
public/client.js
// Use platform authenticator and discoverable credential.
options.authenticatorSelection = {
authenticatorAttachment: 'platform',
requireResidentKey: true
}
- Rufen Sie in der nächsten Zeile die Methode
navigator.credentials.create()auf, um Anmeldedaten zu erstellen.
public/client.js
// Invoke the WebAuthn create() method.
const cred = await navigator.credentials.create({
publicKey: options,
});
Mit diesem Aufruf versucht der Browser, die Identität des Nutzers mit der Displaysperre des Geräts zu bestätigen.
Anmeldedaten beim Serverendpunkt registrieren
Nachdem der Nutzer seine Identität bestätigt hat, wird ein Passkey erstellt und gespeichert. Die Website erhält ein Anmeldedatenobjekt, das einen öffentlichen Schlüssel enthält, den Sie an den Server senden können, um den Passkey zu registrieren.
Das folgende Code-Snippet enthält ein Beispiel für ein Anmeldedatenobjekt:
{
"id": *****,
"rawId": *****,
"type": "public-key",
"response": {
"clientDataJSON": *****,
"attestationObject": *****,
"transports": ["internal", "hybrid"]
},
"authenticatorAttachment": "platform"
}
Die folgende Tabelle ist nicht vollständig, enthält aber die wichtigen Parameter im PublicKeyCredential-Objekt:
Parameter | Textzeilen |
Eine Base64URL-codierte ID des erstellten Passkeys. Anhand dieser ID kann der Browser bei der Authentifizierung feststellen, ob sich auf dem Gerät ein passender Passkey befindet. Dieser Wert muss in der Datenbank im Backend gespeichert werden. | |
Eine | |
Ein | |
Ein | |
Eine Liste der vom Gerät unterstützten Transportmethoden: | |
Gibt |
So senden Sie das Anmeldedatenobjekt an den Server:
- Codieren Sie die binären Parameter der Anmeldedaten als Base64URL, damit sie als String an den Server gesendet werden können. Dazu können Sie
.toJSON()verwenden:
public/client.js
// TODO: Add an ability to create a passkey: Register the credential to the server endpoint.
// Encode and serialize the `PublicKeyCredential`.
const credential = JSON.stringify(cred);
- Senden Sie das Objekt in der nächsten Zeile an den Server:
public/client.js
return await _fetch('/auth/registerResponse', credential);
Wenn Sie das Programm ausführen, gibt der Server HTTP code 200 zurück. Das bedeutet, dass die Anmeldedaten registriert sind.
Jetzt haben Sie die vollständige Funktion registerCredential().
Lösungscode für diesen Abschnitt ansehen
public/client.js
// TODO: Add an ability to create a passkey: Create the registerCredential() function.
export async function registerCredential() {
// TODO: Add an ability to create a passkey: Obtain the challenge and other options from the server endpoint.
const _options = await _fetch('/auth/registerRequest');
// TODO: Add an ability to create a passkey: Create a credential.
// Deserialize and decode the `PublicKeyCredential.parseCreationOptionsFromJSON()`.
const options = PublicKeyCredential.parseCreationOptionsFromJSON(_options);
// Use platform authenticator and discoverable credential.
options.authenticatorSelection = {
authenticatorAttachment: 'platform',
requireResidentKey: true
}
// Invoke the WebAuthn create() method.
const cred = await navigator.credentials.create({
publicKey: options,
});
// TODO: Add an ability to create a passkey: Register the credential to the server endpoint.
// Encode and serialize the `PublicKeyCredential`.
const credential = JSON.stringify(cred);
return await _fetch('/auth/registerResponse', credential);
};
4. UI zum Registrieren und Verwalten von Passkey-Anmeldedaten erstellen
Nachdem die registerCredential()-Funktion verfügbar ist, benötigen Sie eine Schaltfläche, um sie aufzurufen. Außerdem müssen Sie eine Liste der registrierten Passkeys anzeigen.

Platzhalter-HTML hinzufügen
- Rufen Sie in Ihrem Editor die Datei
views/home.htmlauf. - Fügen Sie nach dem entsprechenden Kommentar einen UI-Platzhalter hinzu, in dem eine Schaltfläche zum Registrieren eines Passkeys und eine Liste von Passkeys angezeigt werden:
views/home.html
<!-- TODO: Add an ability to create a passkey: Add placeholder HTML. -->
<section>
<h3>Your registered passkeys:</h3>
<div id="list"></div>
</section>
<p id="message" class="instructions"></p>
<mdui-button id="create-passkey" class="hidden" icon="fingerprint" type="button">Create a passkey</mdui-button>
Das Element div#list ist der Platzhalter für die Liste.
Passkey-Unterstützung prüfen
Damit die Option zum Erstellen eines Passkeys nur Nutzern mit Geräten angezeigt wird, die Passkeys unterstützen, müssen Sie zuerst prüfen, ob WebAuthn verfügbar ist. Wenn ja, müssen Sie die hidden-Klasse entfernen, damit die Schaltfläche Passkey erstellen angezeigt wird.
So prüfen Sie, ob eine Umgebung Passkeys unterstützt:
- Schreiben Sie am Ende der Datei
views/home.htmlnach dem relevanten Kommentar eine Bedingung, die ausgeführt wird, wennwindow.PublicKeyCredential,PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailableundPublicKeyCredential.isConditionalMediationAvailabletruesind.
views/home.html
// TODO: Add an ability to create a passkey: Check for passkey support.
const createPasskey = $('#create-passkey');
// Feature detections
if (window.PublicKeyCredential &&
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable &&
PublicKeyCredential.isConditionalMediationAvailable) {
- Prüfen Sie im Hauptteil der Bedingung, ob das Gerät einen Passkey erstellen kann, und dann, ob der Passkey beim automatischen Ausfüllen eines Formulars vorgeschlagen werden kann.
views/home.html
try {
const capabilities = await PublicKeyCredential.getClientCapabilities();
// Is conditional UI available in this browser?
if (capabilities.conditionalGet === true &&
capabilities.passkeyPlatformAuthenticator === true) {
- Wenn alle Bedingungen erfüllt sind, wird die Schaltfläche zum Erstellen eines Passkeys angezeigt. Andernfalls wird eine Warnmeldung angezeigt.
views/home.html
createPasskey.classList.remove('hidden');
} else {
// If conditional UI isn't available, show a message.
$('#message').innerText = 'This device does not support passkeys.';
}
} catch (e) {
console.error(e);
}
} else {
// If WebAuthn isn't available, show a message.
$('#message').innerText = 'This device does not support passkeys.';
}
Registrierte Passkeys in einer Liste rendern
- Definieren Sie eine
renderCredentials()-Funktion, die registrierte Passkeys vom Server abruft und in einer Liste rendert. Glücklicherweise haben Sie bereits den Serverendpunkt/auth/getKeys, um registrierte Passkeys für den angemeldeten Nutzer abzurufen.
views/home.html
// TODO: Add an ability to create a passkey: Render registered passkeys in a list.
async function renderCredentials() {
const res = await _fetch('/auth/getKeys');
const list = $('#list');
const creds = res.length > 0 ? html`
<mdui-list>
${res.map(cred => html`
<mdui-list-item>
${cred.name || 'Unnamed'}
<mdui-button-icon data-cred-id="${cred.id}" data-name="${cred.name || 'Unnamed'}" @click="${rename}" icon="edit" slot="end-icon"></mdui-button-icon>
<mdui-button-icon data-cred-id="${cred.id}" @click="${remove}" icon="delete" slot="end-icon"></mdui-button-icon>
</mdui-list-item>`)}
</mdui-list>` : html`
<mdui-list>
<mdui-list-item>No credentials found.</mdui-list-item>
</mdui-list>`;
render(creds, list);
};
- Rufen Sie in der nächsten Zeile die Funktion
renderCredentials()auf, um registrierte Passkeys anzuzeigen, sobald der Nutzer auf der Seite/homelandet.
views/home.html
renderCredentials();
Passkey erstellen und registrieren
Wenn Sie einen Passkey erstellen und registrieren möchten, müssen Sie die Funktion registerCredential() aufrufen, die Sie zuvor implementiert haben.
So lösen Sie die registerCredential()-Funktion aus, wenn Sie auf die Schaltfläche Passkey erstellen klicken:
- Suchen Sie in der Datei nach dem Platzhalter-HTML nach der folgenden
import-Anweisung:
views/home.html
import {
$,
_fetch,
loading,
updateCredential,
unregisterCredential,
} from '/client.js';
- Fügen Sie am Ende des Texts der
import-Anweisung die FunktionregisterCredential()ein.
views/home.html
// TODO: Add an ability to create a passkey: Create and register a passkey.
import {
$,
_fetch,
loading,
updateCredential,
unregisterCredential,
registerCredential
} from '/client.js';
- Definieren Sie am Ende der Datei nach dem relevanten Kommentar eine
register()-Funktion, die dieregisterCredential()-Funktion und eine Lade-UI aufruft undrenderCredentials()nach einer Registrierung aufruft. Hier wird klargestellt, dass der Browser einen Passkey erstellt und eine Fehlermeldung anzeigt, wenn etwas schiefgeht.
views/home.html
// TODO: Add an ability to create a passkey: Create and register a passkey.
async function register() {
try {
// Start the loading UI.
loading.start();
// Start creating a passkey.
await registerCredential();
// Stop the loading UI.
loading.stop();
// Render the updated passkey list.
renderCredentials();
- Fangen Sie Ausnahmen im Hauptteil der
register()-Funktion ab. Die Methodenavigator.credentials.create()löst einenInvalidStateError-Fehler aus, wenn auf dem Gerät bereits ein Passkey vorhanden ist. Dies wird mit demexcludeCredentials-Array untersucht. In diesem Fall wird dem Nutzer eine entsprechende Meldung angezeigt. Außerdem wird einNotAllowedError-Fehler ausgegeben, wenn der Nutzer den Authentifizierungsdialog schließt. In diesem Fall ignorieren Sie sie einfach.
views/home.html
} catch (e) {
// Stop the loading UI.
loading.stop();
// An InvalidStateError indicates that a passkey already exists on the device.
if (e.name === 'InvalidStateError') {
alert('A passkey already exists for this device.');
// A NotAllowedError indicates that the user canceled the operation.
} else if (e.name === 'NotAllowedError') {
Return;
// Show other errors in an alert.
} else {
alert(e.message);
console.error(e);
}
}
};
- Hängen Sie in der Zeile nach der
register()-Funktion dieregister()-Funktion an einclick-Ereignis für die Schaltfläche Passkey erstellen an.
views/home.html
createPasskey.addEventListener('click', register);
Lösungscode für diesen Abschnitt ansehen
views/home.html
<!-- TODO: Add an ability to create a passkey: Add placeholder HTML. -->
<section>
<h3>Your registered passkeys:</h3>
<div id="list"></div>
</section>
<p id="message" class="instructions"></p>
<mdui-button id="create-passkey" icon="fingerprint" type="button">Create a passkey</mdui-button>
views/home.html
// TODO: Add an ability to create a passkey: Create and register a passkey.
import {
$,
_fetch,
loading,
updateCredential,
unregisterCredential,
registerCredential
} from '/client.js';
views/home.html
// TODO: Add an ability to create a passkey: Check for passkey support.
const createPasskey = $('#create-passkey');
// Is WebAuthn available in this browser?
if (window.PublicKeyCredential &&
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable &&
PublicKeyCredential.isConditionalMediationAvailable) {
try {
const capabilities = await PublicKeyCredential.getClientCapabilities();
// Is conditional UI available in this browser?
if (capabilities.conditionalGet === true &&
capabilities.passkeyPlatformAuthenticator === true) {
// If conditional UI is available, reveal the Create a passkey button.
createPasskey.classList.remove('hidden');
} else {
// If conditional UI isn't available, show a message.
$('#message').innerText = 'This device does not support passkeys.';
}
} catch (e) {
console.error(e);
}
} else {
// If WebAuthn isn't available, show a message.
$('#message').innerText = 'This device does not support passkeys.';
}
// TODO: Add an ability to create a passkey: Render registered passkeys in a list.
async function renderCredentials() {
const res = await _fetch('/auth/getKeys');
const list = $('#list');
const creds = html`${res.length > 0 ? html`
<mdui-list>
${res.map(cred => html`
<mdui-list-item>
${cred.name || 'Unnamed'}
<mdui-button-icon data-cred-id="${cred.id}" data-name="${cred.name || 'Unnamed'}" @click="${rename}" icon="edit" slot="end-icon"></mdui-button-icon>
<mdui-button-icon data-cred-id="${cred.id}" @click="${remove}" icon="delete" slot="end-icon"></mdui-button-icon>
</mdui-list-item>`)}
</mdui-list>` : html`
<mdui-list>
<mdui-list-item>No credentials found.</mdui-list-item>
</mdui-list>`}`;
render(creds, list);
};
renderCredentials();
// TODO: Add an ability to create a passkey: Create and register a passkey.
async function register() {
try {
// Start the loading UI.
loading.start();
// Start creating a passkey.
await registerCredential();
// Stop the loading UI.
loading.stop();
// Render the updated passkey list.
renderCredentials();
} catch (e) {
// Stop the loading UI.
loading.stop();
// An InvalidStateError indicates that a passkey already exists on the device.
if (e.name === 'InvalidStateError') {
alert('A passkey already exists for this device.');
// A NotAllowedError indicates the user canceled the operation.
} else if (e.name === 'NotAllowedError') {
return;
// Show other errors in an alert.
} else {
alert(e.message);
console.error(e);
}
}
};
createPasskey.addEventListener('click', register);
Jetzt ausprobieren
Wenn Sie alle bisherigen Schritte ausgeführt haben, haben Sie die Möglichkeit implementiert, Passkeys auf der Website zu erstellen, zu registrieren und anzuzeigen.
So probieren Sie es aus:
- Melden Sie sich auf der Website mit einem zufälligen Nutzernamen und Passwort an.
- Klicken Sie auf Passkey erstellen.
- Bestätigen Sie Ihre Identität mit der Displaysperre des Geräts.
- Prüfen Sie, ob ein Passkey registriert und im Abschnitt Ihre registrierten Passkeys der Webseite angezeigt wird.

Registrierte Passkeys umbenennen und entfernen
Sie sollten die registrierten Passkeys in der Liste umbenennen oder löschen können. Sie können sich den Code im Codelab ansehen, um zu sehen, wie er funktioniert.
In Chrome können Sie registrierte Passkeys unter chrome://settings/passkeys auf dem Computer oder über den Passwortmanager in den Einstellungen auf Android-Geräten entfernen.
Informationen zum Umbenennen und Entfernen registrierter Passkeys auf anderen Plattformen finden Sie auf den entsprechenden Supportseiten für diese Plattformen.
5. Authentifizierung mit einem Passkey hinzufügen
Nutzer können jetzt einen Passkey erstellen und registrieren und ihn als sichere Authentifizierungsmethode für Ihre Website verwenden. Jetzt müssen Sie Ihrer Website eine Passkey-Authentifizierungsfunktion hinzufügen.
Funktion authenticate() erstellen
- Erstellen Sie in der Datei
public/client.jsnach dem entsprechenden Kommentar eine Funktion namensauthenticate(), die den Nutzer lokal und dann auf dem Server authentifiziert:
public/client.js
// TODO: Add an ability to authenticate with a passkey: Create the authenticate() function.
export async function authenticate() {
// TODO: Add an ability to authenticate with a passkey: Obtain the challenge and other options from the server endpoint.
// TODO: Add an ability to authenticate with a passkey: Locally verify the user and get a credential.
// TODO: Add an ability to authenticate with a passkey: Verify the credential.
};
Herausforderung und andere Optionen vom Serverendpunkt abrufen
Bevor Sie den Nutzer zur Authentifizierung auffordern, müssen Sie Parameter anfordern, die in WebAuthn vom Server übergeben werden sollen, einschließlich einer Challenge.
- Rufen Sie im Text der Funktion
authenticate()nach dem entsprechenden Kommentar die Funktion_fetch()auf, um einePOST-Anfrage an den Server zu senden:
public/client.js
// TODO: Add an ability to authenticate with a passkey: Obtain the challenge and other options from the server endpoint.
// Base64URL decode the challenge.
const options = PublicKeyCredential.parseRequestOptionsFromJSON(_options);
Der Server dieses Codelabs ist so konzipiert, dass er JSON zurückgibt, das dem PublicKeyCredentialRequestOptions-Wörterbuch, das an die WebAuthn-navigator.credentials.get()-API übergeben wird, so ähnlich wie möglich ist. Das folgende Code-Snippet enthält Beispieloptionen, die Sie erhalten sollten:
{
"challenge": *****,
"rpId": "localhost",
"allowCredentials": []
}
Die folgende Tabelle ist nicht vollständig, enthält aber die wichtigen Parameter im PublicKeyCredentialRequestOptions-Dictionary:
Parameter | Textzeilen |
Eine vom Server generierte Challenge in einem | |
Eine RP‑ID ist eine Domain. Eine Website kann entweder ihre Domain oder ein registrierbares Suffix angeben. Dieser Wert muss mit dem Parameter | |
Mit dieser Eigenschaft werden Authentifikatoren gefunden, die für diese Authentifizierung infrage kommen. Übergeben Sie ein leeres Array oder lassen Sie es nicht angegeben, damit der Browser eine Kontoauswahl anzeigt. Weitere Informationen | |
Legen Sie den Wert auf |
Nutzer lokal bestätigen und Anmeldedaten abrufen
- Konvertieren Sie im Funktionskörper der Funktion
authenticate()nach dem relevanten Kommentar den Parameterchallengezurück in Binärformat:
public/client.js
// TODO: Add an ability to authenticate with a passkey: Locally verify the user and get a credential.
// Base64URL decode the challenge.
options.challenge = base64url.decode(options.challenge);
- Übergeben Sie ein leeres Array an den Parameter
allowCredentials, um bei der Authentifizierung eines Nutzers eine Kontoauswahl zu öffnen:
public/client.js
// An empty allowCredentials array invokes an account selector by discoverable credentials.
options.allowCredentials = [];
Die Kontoauswahl verwendet die mit dem Passkey gespeicherten Informationen des Nutzers.
- Rufen Sie die Methode
navigator.credentials.get()zusammen mit der Optionmediation: 'conditional'auf:
public/client.js
// Invoke the WebAuthn get() method.
const cred = await navigator.credentials.get({
publicKey: options,
// Request a conditional UI.
mediation: 'conditional'
});
Mit dieser Option wird der Browser angewiesen, Passkeys bedingt als Teil der automatischen Formularausfüllung vorzuschlagen.
Anmeldedaten bestätigen
Nachdem der Nutzer seine Identität lokal bestätigt hat, sollten Sie ein Anmeldedatenobjekt mit einer Signatur erhalten, die Sie auf dem Server überprüfen können.
Das folgende Code-Snippet enthält ein Beispiel für ein PublicKeyCredential-Objekt:
{
"id": *****,
"rawId": *****,
"type": "public-key",
"response": {
"clientDataJSON": *****,
"authenticatorData": *****,
"signature": *****,
"userHandle": *****
},
authenticatorAttachment: "platform"
}
Die folgende Tabelle ist nicht vollständig, enthält aber die wichtigen Parameter im PublicKeyCredential-Objekt:
Parameter | Textzeilen |
Die Base64URL-codierte ID des authentifizierten Passkey-Anmeldedaten. | |
Eine | |
Ein | |
Ein | |
Ein | |
Ein | |
Gibt einen |
So senden Sie das Anmeldedatenobjekt an den Server:
- Codieren Sie im Hauptteil der Funktion
authenticate()nach dem relevanten Kommentar die binären Parameter der Anmeldedaten, damit sie als String an den Server gesendet werden können. Dazu können Sie.toJSON()verwenden:
public/client.js
// TODO: Add an ability to authenticate with a passkey: Verify the credential.
// Encode and serialize the `PublicKeyCredential`.
const credential = JSON.stringify(cred);
- Senden Sie das Objekt an den Server:
public/client.js
return await _fetch(`/auth/signinResponse`, credential);
Wenn Sie das Programm ausführen, gibt der Server HTTP code 200 zurück. Das bedeutet, dass die Anmeldedaten bestätigt wurden.
Sie haben jetzt die vollständige Funktion authentication().
Lösungscode für diesen Abschnitt ansehen
public/client.js
// TODO: Add an ability to authenticate with a passkey: Create the authenticate() function.
export async function authenticate() {
// TODO: Add an ability to authenticate with a passkey: Obtain the
challenge and other options from the server endpoint.
const options = await _fetch('/auth/signinRequest');
// TODO: Add an ability to authenticate with a passkey: Locally verify
the user and get a credential.
// Base64URL decode the challenge.
options.challenge = base64url.decode(options.challenge);
// The empty allowCredentials array invokes an account selector
by discoverable credentials.
options.allowCredentials = [];
// Invoke the WebAuthn get() function.
const cred = await navigator.credentials.get({
publicKey: options,
// Request a conditional UI.
mediation: 'conditional'
});
// TODO: Add an ability to authenticate with a passkey: Verify the credential.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// Base64URL encode some values.
const clientDataJSON = base64url.encode(cred.response.clientDataJSON);
const authenticatorData =
base64url.encode(cred.response.authenticatorData);
const signature = base64url.encode(cred.response.signature);
const userHandle = base64url.encode(cred.response.userHandle);
credential.response = {
clientDataJSON,
authenticatorData,
signature,
userHandle,
};
return await _fetch(`/auth/signinResponse`, credential);
};
6. Passkeys zur Browser-Autofill-Funktion hinzufügen
Wenn der Nutzer zurückkehrt, soll er sich so einfach und sicher wie möglich anmelden können. Wenn Sie der Anmeldeseite die Schaltfläche Mit Passkey anmelden hinzufügen, kann der Nutzer darauf tippen, im Kontoauswahlfeld des Browsers einen Passkey auswählen und die Identität über die Displaysperre bestätigen.
Die Umstellung von Passwörtern auf Passkeys erfolgt jedoch nicht für alle Nutzer gleichzeitig. Das bedeutet, dass Sie Passwörter erst entfernen können, wenn alle Nutzer auf Passkeys umgestellt haben. Bis dahin müssen Sie das Anmeldeformular mit Passwort beibehalten. Wenn Sie jedoch ein Passwortformular und eine Passkey-Schaltfläche einfügen, müssen Nutzer unnötigerweise auswählen, welche Methode sie für die Anmeldung verwenden möchten. Im Idealfall ist die Anmeldung unkompliziert.
Hier kommt eine bedingte Benutzeroberfläche ins Spiel. Eine bedingte Benutzeroberfläche ist eine WebAuthn-Funktion, mit der Sie ein Formulareingabefeld erstellen können, um zusätzlich zu Passwörtern auch einen Passkey als Teil von Autofill-Elementen vorzuschlagen. Wenn ein Nutzer in den Vorschlägen für die automatische Vervollständigung auf einen Passkey tippt, wird er aufgefordert, die Displaysperre des Geräts zu verwenden, um seine Identität lokal zu bestätigen. Das ist eine nahtlose Nutzererfahrung, da die Nutzeraktion fast identisch mit der einer passwortbasierten Anmeldung ist.

Bedingte Benutzeroberfläche aktivieren
Um eine bedingte Benutzeroberfläche zu aktivieren, müssen Sie lediglich ein webauthn-Token in das Attribut autocomplete eines Eingabefelds einfügen. Wenn das Token festgelegt ist, können Sie die Methode navigator.credentials.get() mit dem String mediation: 'conditional' aufrufen, um die Benutzeroberfläche für die Displaysperre bedingt auszulösen.
- Um eine bedingte Benutzeroberfläche zu aktivieren, ersetzen Sie die vorhandenen Eingabefelder für den Nutzernamen durch den folgenden HTML-Code nach dem entsprechenden Kommentar in der Datei
view/index.html:
view/index.html
<!-- TODO: Add passkeys to the browser autofill: Enable conditional UI. -->
<mdui-text-field id="username" label="Username" name="username" autocomplete="username webauthn" autofocus></mdui-text-field>
Funktionen erkennen, WebAuthn aufrufen und eine bedingte Benutzeroberfläche aktivieren
- Ersetzen Sie in der Datei
view/index.htmlnach dem entsprechenden Kommentar die vorhandeneimport-Anweisung durch den folgenden Code:
view/index.html
// TODO: Add passkeys to the browser autofill: Detect features, invoke WebAuthn, and enable a conditional UI.
import {
$,
_fetch,
loading,
authenticate
} from "/client.js";
Mit diesem Code wird die Funktion authenticate() importiert, die Sie zuvor implementiert haben.
- Prüfen Sie, ob das
window.PulicKeyCredential-Objekt verfügbar ist und ob diePublicKeyCredential.isConditionalMediationAvailable()-Methode einentrue-Wert zurückgibt. Rufen Sie dann dieauthenticate()-Funktion auf:
view/index.html
// TODO: Add passkeys to the browser autofill: Detect features, invoke WebAuthn, and enable a conditional UI.
if (window.PublicKeyCredential &&
PublicKeyCredential.getClientCapabilities) {
try {
// Is conditional UI available in this browser?
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalGet) {
// If conditional UI is available, invoke the authenticate() function.
const user = await authenticate();
if (user) {
// Proceed only when authentication succeeds.
$("#username").value = user.username;
loading.start();
location.href = "/home";
} else {
throw new Error("User not found.");
}
}
} catch (e) {
loading.stop();
// A NotAllowedError indicates that the user canceled the operation.
if (e.name !== "NotAllowedError") {
console.error(e);
alert(e.message);
}
}
}
Lösungscode für diesen Abschnitt ansehen
view/index.html
<!-- TODO: Add passkeys to the browser autofill: Enable conditional UI. -->
<mdui-text-field id="username" label="Username" name="username" autocomplete="username webauthn" autofocus></mdui-text-field>
view/index.html
// TODO: Add passkeys to the browser autofill: Detect features, invoke WebAuthn, and enable a conditional UI.
import {
$,
_fetch,
loading,
authenticate
} from '/client.js';
view/index.html
// TODO: Add passkeys to the browser autofill: Detect features, invoke WebAuthn, and enable a conditional UI.
// Is WebAuthn available on this browser?
if (window.PublicKeyCredential &&
PublicKeyCredential.getClientCapabilities) {
try {
// Is conditional UI available in this browser?
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalGet) {
// If conditional UI is available, invoke the authenticate() function.
const user = await authenticate();
if (user) {
// Proceed only when authentication succeeds.
$('#username').value = user.username;
loading.start();
location.href = '/home';
} else {
throw new Error('User not found.');
}
}
} catch (e) {
loading.stop();
// A NotAllowedError indicates that the user canceled the operation.
if (e.name !== 'NotAllowedError') {
console.error(e);
alert(e.message);
}
}
}
Jetzt ausprobieren
Sie haben die Erstellung, Registrierung, Anzeige und Authentifizierung von Passkeys auf Ihrer Website implementiert.
So probieren Sie es aus:
- Rufen Sie den Tab „Vorschau“ auf.
- Melden Sie sich gegebenenfalls ab.
- Klicken Sie auf das Textfeld für den Nutzernamen. Ein Dialogfeld wird angezeigt.
- Wählen Sie das Konto aus, mit dem Sie sich anmelden möchten.
- Bestätigen Sie Ihre Identität mit der Displaysperre des Geräts. Sie werden zur Seite
/homeweitergeleitet und sind angemeldet.

7. Glückwunsch!
Sie haben dieses Codelab abgeschlossen. Wenn Sie Fragen haben, stellen Sie sie auf der FIDO-DEV-Mailingliste oder auf Stack Overflow mit dem Tag passkey.