Nutzer mit Credential Manager anmelden

Credential Manager ist eine Jetpack API, die mehrere Anmeldemethoden wie Nutzername und Passwort, Passkeys und Lösungen für die föderierte Anmeldung (z. B. „Über Google anmelden“) in einer einzigen API unterstützt. Dadurch wird die Integration für Entwickler vereinfacht.

Außerdem vereinfacht der Anmeldedaten-Manager die Anmeldung für Nutzer, da die Anmeldeoberfläche für alle Authentifizierungsmethoden identisch ist.

Auf dieser Seite wird das Konzept von Passkeys und die Schritte zur Implementierung von clientseitigem Support für Authentifizierungslösungen, einschließlich Passkeys, mit der Credential Manager API erläutert. Auf der separaten FAQ-Seite finden Sie Antworten auf detailliertere, spezifischere Fragen.

Ihr Feedback ist ein wichtiger Bestandteil der Verbesserung der Credential Manager API. Wenn Sie Probleme finden oder Ideen zur Verbesserung der API haben, können Sie sich über den folgenden Link an uns wenden:

Feedback geben

Passkeys

Passkeys sind ein sichererer und einfacherer Ersatz für Passwörter. Mit Passkeys können sich Nutzer über einen biometrischen Sensor (z. B. Fingerabdruck oder Gesichtserkennung), eine PIN oder ein Muster in Apps und auf Websites anmelden. So wird die Anmeldung vereinfacht und Ihre Nutzer müssen sich keine Nutzernamen oder Passwörter merken.

Passkeys basieren auf WebAuthn (Web Authentication), einem gemeinsam von der FIDO Alliance und dem World Wide Web Consortium (W3C) entwickelten Standard. WebAuthn verwendet die Public-Key-Kryptografie, um den Nutzer zu authentifizieren. Die Website oder Anwendung, auf der sich der Nutzer anmeldet, kann den öffentlichen Schlüssel sehen und speichern, aber niemals den privaten Schlüssel. Der private Schlüssel wird geheim und sicher aufbewahrt. Da der Schlüssel eindeutig ist und mit der Website oder App verknüpft ist, können Passkeys nicht gephisht werden, was die Sicherheit weiter erhöht.

Mit dem Anmeldedaten-Manager können Nutzer Passkeys erstellen und im Google Passwortmanager speichern.

Im Hilfeartikel Nutzerauthentifizierung mit Passkeys erfahren Sie, wie Sie nahtlose Passkey-Authentifizierungsabläufe mit dem Anmeldedaten-Manager implementieren.

Voraussetzungen

Führe die Schritte in diesem Abschnitt aus, um den Anmeldedaten-Manager zu verwenden.

Aktuelle Plattformversion verwenden

Der Credential Manager wird ab Android 4.4 (API-Level 19) unterstützt.

Abhängigkeiten zu Ihrer Anwendung hinzufügen

Fügen Sie dem Build-Skript Ihres App-Moduls die folgenden Abhängigkeiten hinzu:

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.5.0-alpha05")

    // optional - needed for credentials support from play services, for devices running
    // Android 13 and below.
    implementation("androidx.credentials:credentials-play-services-auth:1.5.0-alpha05")
}

Cool

dependencies {
    implementation "androidx.credentials:credentials:1.5.0-alpha05"

    // optional - needed for credentials support from play services, for devices running
    // Android 13 and below.
    implementation "androidx.credentials:credentials-play-services-auth:1.5.0-alpha05"
}

Klassen in der ProGuard-Datei beibehalten

Fügen Sie in der Datei proguard-rules.pro Ihres Moduls die folgenden Anweisungen hinzu:

-if class androidx.credentials.CredentialManager
-keep class androidx.credentials.playservices.** {
  *;
}

Weitere Informationen zum Verkleinern, Verschleißen und Optimieren Ihrer App

Unterstützung für Digital Asset Links hinzufügen

Wenn Sie die Passkey-Unterstützung für Ihre Android-App aktivieren möchten, verknüpfen Sie Ihre App mit einer Website, die Ihrer App gehört. So erklären Sie diese Verknüpfung:

  1. Erstelle eine Digital Asset Links-JSON-Datei. Wenn Sie beispielsweise angeben möchten, dass die Website https://signin.example.com und eine Android-App mit dem Paketnamen com.example Anmeldedaten gemeinsam nutzen können, erstellen Sie eine Datei namens assetlinks.json mit folgendem Inhalt:

    [
      {
        "relation" : [
          "delegate_permission/common.handle_all_urls",
          "delegate_permission/common.get_login_creds"
        ],
        "target" : {
          "namespace" : "android_app",
          "package_name" : "com.example.android",
          "sha256_cert_fingerprints" : [
            SHA_HEX_VALUE
          ]
        }
      }
    ]
    

    Das Feld relation ist ein Array mit einer oder mehreren Strings, die die deklarierte Beziehung beschreiben. Wenn Sie angeben möchten, dass Apps und Websites Anmeldedaten gemeinsam nutzen, geben Sie die Beziehungen als delegate_permission/handle_all_urls und delegate_permission/common.get_login_creds an.

    Das Feld target ist ein Objekt, das das Asset angibt, auf das sich die Erklärung bezieht. Die folgenden Felder identifizieren eine Website:

    namespace web
    site

    Die URL der Website im Format https://domain[:optional_port]. Beispiel: https://www.example.com.

    Die domain muss vollständig qualifiziert sein und optional_port muss weggelassen werden, wenn Port 443 für HTTPS verwendet wird.

    Ein site-Ziel kann nur eine Stammdomain sein. Sie können eine App-Verknüpfung nicht auf ein bestimmtes Unterverzeichnis beschränken. Die URL darf keinen Pfad enthalten, z. B. keinen abschließenden Schrägstrich.

    Subdomains gelten nicht als Übereinstimmung. Wenn Sie also domain als www.example.com angeben, ist die Domain www.counter.example.com nicht mit Ihrer App verknüpft.

    Die folgenden Felder identifizieren eine Android-App:

    namespace android_app
    package_name Der im Manifest der App angegebene Paketname. Beispiel: com.example.android
    sha256_cert_fingerprints Die SHA256-Fingerabdrücke des Signaturzertifikats deiner App.
  2. Hoste die Digital Asset Link-JSON-Datei an folgendem Speicherort auf der Anmeldedomain:

    https://domain[:optional_port]/.well-known/assetlinks.json
    

    Wenn Ihre Anmeldedomain beispielsweise signin.example.com ist, hosten Sie die JSON-Datei unter https://signin.example.com/.well-known/assetlinks.json.

    Der MIME-Typ der Digital Asset Link-Datei muss JSON sein. Achten Sie darauf, dass der Server in der Antwort einen Content-Type: application/json-Header sendet.

  3. Ihr Host muss Google erlauben, Ihre Digital Asset Link-Datei abzurufen. Wenn du eine robots.txt-Datei hast, muss sie es dem Googlebot-Agent ermöglichen, /.well-known/assetlinks.json abzurufen. Die meisten Websites können jedem automatisierten Agenten erlauben, Dateien im Pfad /.well-known/ abzurufen, damit andere Dienste auf die Metadaten in diesen Dateien zugreifen können:

    User-agent: *
    Allow: /.well-known/
    
  4. Fügen Sie der Manifestdatei unter <application> die folgende Zeile hinzu:

    <meta-data android:name="asset_statements" android:resource="@string/asset_statements" />
    
  5. Wenn du die Passwort-Anmeldung über den Anmeldedaten-Manager verwendest, folge diesem Schritt, um die Verknüpfung digitaler Assets im Manifest zu konfigurieren. Dieser Schritt ist nicht erforderlich, wenn Sie nur Passkeys verwenden.

    Deklarieren Sie die Verknüpfung in der Android-App. Fügen Sie ein Objekt hinzu, das die zu ladenden assetlinks.json-Dateien angibt. Apostrophe und Anführungszeichen im String müssen maskiert werden. Beispiel:

    <string name="asset_statements" translatable="false">
    [{
      \"include\": \"https://signin.example.com/.well-known/assetlinks.json\"
    }]
    </string>
    
    > GET /.well-known/assetlinks.json HTTP/1.1
    > User-Agent: curl/7.35.0
    > Host: signin.example.com
    
    < HTTP/1.1 200 OK
    < Content-Type: application/json
    

Anmeldedaten-Manager konfigurieren

Zum Konfigurieren und Initialisieren eines CredentialManager-Objekts fügen Sie eine Logik wie die folgende hinzu:

Kotlin

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
val credentialManager = CredentialManager.create(context)

Java

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
CredentialManager credentialManager = CredentialManager.create(context)

Anmeldedatenfelder angeben

Unter Android 14 und höher kann das Attribut isCredential verwendet werden, um Anmeldedatenfelder wie Nutzernamen- oder Passwortfelder anzugeben. Dieses Attribut gibt an, dass es sich bei dieser Ansicht um ein Anmeldedaten-Feld handelt, das mit dem Anmeldedaten-Manager und Anmeldedatenanbietern von Drittanbietern verwendet werden soll. Außerdem trägt es dazu bei, dass Autofill-Dienste bessere Autofill-Vorschläge machen können. Wenn die App die Credential Manager API verwendet, wird das untere Steuerfeld des Credential Managers mit den verfügbaren Anmeldedaten angezeigt. Das Autofill-Dialogfeld für Nutzernamen oder Passwort muss dann nicht mehr angezeigt werden. Ebenso muss das Dialogfeld zum Speichern von Passwörtern nicht angezeigt werden, da die App die Credential Manager API zum Speichern der Anmeldedaten anfordert.

Um das Attribut isCredential zu verwenden, fügen Sie es den entsprechenden Datenansichten hinzu:

<TextView
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:isCredential="true"
...
 />

Nutzer anmelden

So rufen Sie alle Passkey- und Passwortoptionen ab, die mit dem Konto des Nutzers verknüpft sind:

  1. Initialisieren Sie die Optionen für die Passwort- und Passkey-Authentifizierung:

    Kotlin

    // Retrieves the user's saved password for your app from their
    // password provider.
    val getPasswordOption = GetPasswordOption()
    
    // Get passkey from the user's public key credential provider.
    val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
        requestJson = requestJson
    )

    Java

    // Retrieves the user's saved password for your app from their
    // password provider.
    GetPasswordOption getPasswordOption = new GetPasswordOption();
    
    // Get passkey from the user's public key credential provider.
    GetPublicKeyCredentialOption getPublicKeyCredentialOption =
            new GetPublicKeyCredentialOption(requestJson);
  2. Verwende die im vorherigen Schritt abgerufenen Optionen, um die Anmeldeanfrage zu erstellen.

    Kotlin

    val getCredRequest = GetCredentialRequest(
        listOf(getPasswordOption, getPublicKeyCredentialOption)
    )

    Java

    GetCredentialRequest getCredRequest = new GetCredentialRequest.Builder()
        .addCredentialOption(getPasswordOption)
        .addCredentialOption(getPublicKeyCredentialOption)
        .build();
  3. Starten Sie den Anmeldevorgang:

    Kotlin

    coroutineScope.launch {
        try {
            val result = credentialManager.getCredential(
                // Use an activity-based context to avoid undefined system UI
                // launching behavior.
                context = activityContext,
                request = getCredRequest
            )
            handleSignIn(result)
        } catch (e : GetCredentialException) {
            handleFailure(e)
        }
    }
    
    fun handleSignIn(result: GetCredentialResponse) {
        // Handle the successfully returned credential.
        val credential = result.credential
    
        when (credential) {
            is PublicKeyCredential -> {
                val responseJson = credential.authenticationResponseJson
                // Share responseJson i.e. a GetCredentialResponse on your server to
                // validate and  authenticate
            }
            is PasswordCredential -> {
                val username = credential.id
                val password = credential.password
                // Use id and password to send to your server to validate
                // and authenticate
            }
          is CustomCredential -> {
              // If you are also using any external sign-in libraries, parse them
              // here with the utility functions provided.
              if (credential.type == ExampleCustomCredential.TYPE)  {
              try {
                  val ExampleCustomCredential = ExampleCustomCredential.createFrom(credential.data)
                  // Extract the required credentials and complete the authentication as per
                  // the federated sign in or any external sign in library flow
                  } catch (e: ExampleCustomCredential.ExampleCustomCredentialParsingException) {
                      // Unlikely to happen. If it does, you likely need to update the dependency
                      // version of your external sign-in library.
                      Log.e(TAG, "Failed to parse an ExampleCustomCredential", e)
                  }
              } else {
                // Catch any unrecognized custom credential type here.
                Log.e(TAG, "Unexpected type of credential")
              }
            } else -> {
                // Catch any unrecognized credential type here.
                Log.e(TAG, "Unexpected type of credential")
            }
        }
    }

    Java

    credentialManager.getCredentialAsync(
        // Use activity based context to avoid undefined
        // system UI launching behavior
        activity,
        getCredRequest,
        cancellationSignal,
        <executor>,
        new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() {
            @Override
            public void onResult(GetCredentialResponse result) {
                handleSignIn(result);
            }
    
            @Override
            public void onError(GetCredentialException e) {
                handleFailure(e);
            }
        }
    );
    
    public void handleSignIn(GetCredentialResponse result) {
        // Handle the successfully returned credential.
        Credential credential = result.getCredential();
        if (credential instanceof PublicKeyCredential) {
            String responseJson = ((PublicKeyCredential) credential).getAuthenticationResponseJson();
            // Share responseJson i.e. a GetCredentialResponse on your server to validate and authenticate
        } else if (credential instanceof PasswordCredential) {
            String username = ((PasswordCredential) credential).getId();
            String password = ((PasswordCredential) credential).getPassword();
            // Use id and password to send to your server to validate and authenticate
        } else if (credential instanceof CustomCredential) {
            if (ExampleCustomCredential.TYPE.equals(credential.getType())) {
                try {
                    ExampleCustomCredential customCred = ExampleCustomCredential.createFrom(customCredential.getData());
                    // Extract the required credentials and complete the
                    // authentication as per the federated sign in or any external
                    // sign in library flow
                } catch (ExampleCustomCredential.ExampleCustomCredentialParsingException e) {
                    // Unlikely to happen. If it does, you likely need to update the
                    // dependency version of your external sign-in library.
                    Log.e(TAG, "Failed to parse an ExampleCustomCredential", e);
                }
            } else {
                // Catch any unrecognized custom credential type here.
                Log.e(TAG, "Unexpected type of credential");
            }
        } else {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential");
        }
    }

Das folgende Beispiel zeigt, wie Sie die JSON-Anfrage formatieren, wenn Sie einen Passkey erhalten:

{
  "challenge": "T1xCsnxM2DNL2KdK5CLa6fMhD7OBqho6syzInk_n-Uo",
  "allowCredentials": [],
  "timeout": 1800000,
  "userVerification": "required",
  "rpId": "credential-manager-app-test.glitch.me"
}

Das folgende Beispiel zeigt, wie eine JSON-Antwort aussehen könnte, nachdem Sie Anmeldedaten mit öffentlichem Schlüssel abgerufen haben:

{
  "id": "KEDetxZcUfinhVi6Za5nZQ",
  "type": "public-key",
  "rawId": "KEDetxZcUfinhVi6Za5nZQ",
  "response": {
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiVDF4Q3NueE0yRE5MMktkSzVDTGE2Zk1oRDdPQnFobzZzeXpJbmtfbi1VbyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
    "authenticatorData": "j5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGQdAAAAAA",
    "signature": "MEUCIQCO1Cm4SA2xiG5FdKDHCJorueiS04wCsqHhiRDbbgITYAIgMKMFirgC2SSFmxrh7z9PzUqr0bK1HZ6Zn8vZVhETnyQ",
    "userHandle": "2HzoHm_hY0CjuEESY9tY6-3SdjmNHOoNqaPDcZGzsr0"
  }
}

Ausnahmen behandeln, wenn keine Anmeldedaten verfügbar sind

Es kann vorkommen, dass dem Nutzer keine Anmeldedaten zur Verfügung stehen oder er keine Einwilligung zur Verwendung verfügbarer Anmeldedaten erteilt. Wenn getCredential() aufgerufen wird und keine Anmeldedaten gefunden werden, wird NoCredentialException zurückgegeben. In diesem Fall sollten die NoCredentialException-Instanzen im Code verarbeitet werden.

Kotlin

try {
  val credential = credentialManager.getCredential(credentialRequest)
} catch (e: NoCredentialException) {
  Log.e("CredentialManager", "No credential available", e)
}

Java

try {
  Credential credential = credentialManager.getCredential(credentialRequest);
} catch (NoCredentialException e) {
  Log.e("CredentialManager", "No credential available", e);
}

Unter Android 14 oder höher kannst du die Latenz beim Anzeigen der Kontoauswahl verringern, indem du die Methode prepareGetCredential() vor dem Aufruf von getCredential() verwendest.

Kotlin

val response = credentialManager.prepareGetCredential(
  GetCredentialRequest(
    listOf(
      <getPublicKeyCredentialOption>,
      <getPasswordOption>
    )
  )
}

Java

GetCredentialResponse response = credentialManager.prepareGetCredential(
  new GetCredentialRequest(
    Arrays.asList(
      new PublicKeyCredentialOption(),
      new PasswordOption()
    )
  )
);

Die Methode prepareGetCredential() ruft keine UI-Elemente auf. Sie hilft Ihnen nur bei der Vorbereitung, damit Sie den verbleibenden Vorgang zum Abrufen von Anmeldedaten (mit Benutzeroberflächen) später über die getCredential() API starten können.

Die im Cache gespeicherten Daten werden in einem PrepareGetCredentialResponse-Objekt zurückgegeben. Wenn Anmeldedaten vorhanden sind, werden die Ergebnisse im Cache gespeichert. Sie können dann später die verbleibende getCredential() API starten, um die Kontoauswahl mit den im Cache gespeicherten Daten aufzurufen.

Registrierungsvorgang

Sie können einen Nutzer entweder mit einem Passkey oder einem Passwort für die Authentifizierung registrieren.

Passkey erstellen

Wenn Sie Nutzern die Möglichkeit geben möchten, einen Passkey zu registrieren und zur erneuten Authentifizierung zu verwenden, registrieren Sie die Anmeldedaten eines Nutzers mit einem CreatePublicKeyCredentialRequest-Objekt.

Kotlin

fun createPasskey(requestJson: String, preferImmediatelyAvailableCredentials: Boolean) {
    val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest(
        // Contains the request in JSON format. Uses the standard WebAuthn
        // web JSON spec.
        requestJson = requestJson,
        // Defines whether you prefer to use only immediately available
        // credentials, not hybrid credentials, to fulfill this request.
        // This value is false by default.
        preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials,
    )

    // Execute CreateCredentialRequest asynchronously to register credentials
    // for a user account. Handle success and failure cases with the result and
    // exceptions, respectively.
    coroutineScope.launch {
        try {
            val result = credentialManager.createCredential(
                // Use an activity-based context to avoid undefined system
                // UI launching behavior
                context = activityContext,
                request = createPublicKeyCredentialRequest,
            )
            handlePasskeyRegistrationResult(result)
        } catch (e : CreateCredentialException){
            handleFailure(e)
        }
    }
}

fun handleFailure(e: CreateCredentialException) {
    when (e) {
        is CreatePublicKeyCredentialDomException -> {
            // Handle the passkey DOM errors thrown according to the
            // WebAuthn spec.
            handlePasskeyError(e.domError)
        }
        is CreateCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to register the credential.
        }
        is CreateCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is CreateCredentialProviderConfigurationException -> {
            // Your app is missing the provider configuration dependency.
            // Most likely, you're missing the
            // "credentials-play-services-auth" module.
        }
        is CreateCredentialUnknownException -> ...
        is CreateCredentialCustomException -> {
            // You have encountered an error from a 3rd-party SDK. If you
            // make the API call with a request object that's a subclass of
            // CreateCustomCredentialRequest using a 3rd-party SDK, then you
            // should check for any custom exception type constants within
            // that SDK to match with e.type. Otherwise, drop or log the
            // exception.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java.name}")
    }
}

Java

public void createPasskey(String requestJson, boolean preferImmediatelyAvailableCredentials) {
    CreatePublicKeyCredentialRequest createPublicKeyCredentialRequest =
            // `requestJson` contains the request in JSON format. Uses the standard
            // WebAuthn web JSON spec.
            // `preferImmediatelyAvailableCredentials` defines whether you prefer
            // to only use immediately available credentials, not  hybrid credentials,
            // to fulfill this request. This value is false by default.
            new CreatePublicKeyCredentialRequest(
                requestJson, preferImmediatelyAvailableCredentials);

    // Execute CreateCredentialRequest asynchronously to register credentials
    // for a user account. Handle success and failure cases with the result and
    // exceptions, respectively.
    credentialManager.createCredentialAsync(
        // Use an activity-based context to avoid undefined system
        // UI launching behavior
        requireActivity(),
        createPublicKeyCredentialRequest,
        cancellationSignal,
        executor,
        new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() {
            @Override
            public void onResult(CreateCredentialResponse result) {
                handleSuccessfulCreatePasskeyResult(result);
            }

            @Override
            public void onError(CreateCredentialException e) {
                if (e instanceof CreatePublicKeyCredentialDomException) {
                    // Handle the passkey DOM errors thrown according to the
                    // WebAuthn spec.
                    handlePasskeyError(((CreatePublicKeyCredentialDomException)e).getDomError());
                } else if (e instanceof CreateCredentialCancellationException) {
                    // The user intentionally canceled the operation and chose not
                    // to register the credential.
                } else if (e instanceof CreateCredentialInterruptedException) {
                    // Retry-able error. Consider retrying the call.
                } else if (e instanceof CreateCredentialProviderConfigurationException) {
                    // Your app is missing the provider configuration dependency.
                    // Most likely, you're missing the
                    // "credentials-play-services-auth" module.
                } else if (e instanceof CreateCredentialUnknownException) {
                } else if (e instanceof CreateCredentialCustomException) {
                    // You have encountered an error from a 3rd-party SDK. If
                    // you make the API call with a request object that's a
                    // subclass of
                    // CreateCustomCredentialRequest using a 3rd-party SDK,
                    // then you should check for any custom exception type
                    // constants within that SDK to match with e.type.
                    // Otherwise, drop or log the exception.
                } else {
                  Log.w(TAG, "Unexpected exception type "
                          + e.getClass().getName());
                }
            }
        }
    );
}

JSON-Anfrage formatieren

Nachdem Sie einen Passkey erstellt haben, müssen Sie ihn mit dem Konto eines Nutzers verknüpfen und den öffentlichen Schlüssel des Passkeys auf Ihrem Server speichern. Das folgende Codebeispiel zeigt, wie die JSON-Anfrage beim Erstellen eines Passkeys formatiert wird.

In diesem Blogpost zur nahtlosen Authentifizierung in Ihren Apps erfahren Sie, wie Sie Ihre JSON-Anfrage formatieren, wenn Sie Passkeys erstellen und sich mit Passkeys authentifizieren. Außerdem wird erläutert, warum Passwörter keine effektive Authentifizierungslösung sind, wie Sie vorhandene biometrische Anmeldedaten nutzen, Ihre App mit einer eigenen Website verknüpfen, wie Sie Passkeys erstellen und wie Sie sich mit Passkeys authentifizieren.

{
  "challenge": "abc123",
  "rp": {
    "name": "Credential Manager example",
    "id": "credential-manager-test.example.com"
  },
  "user": {
    "id": "def456",
    "name": "helloandroid@gmail.com",
    "displayName": "helloandroid@gmail.com"
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    },
    {
      "type": "public-key",
      "alg": -257
    }
  ],
  "timeout": 1800000,
  "attestation": "none",
  "excludeCredentials": [
    {"id": "ghi789", "type": "public-key"},
    {"id": "jkl012", "type": "public-key"}
  ],
  "authenticatorSelection": {
    "authenticatorAttachment": "platform",
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

Werte für „authenticatorAttachment“ festlegen

Der Parameter authenticatorAttachment kann nur beim Erstellen von Anmeldedaten festgelegt werden. Sie können platform, cross-platform oder keinen Wert angeben. In den meisten Fällen wird kein Wert empfohlen.

  • platform: Wenn Sie das aktuelle Gerät des Nutzers registrieren oder einen Passwortnutzer nach der Anmeldung zum Upgrade auf Passkeys auffordern möchten, legen Sie authenticatorAttachment auf platform fest.
  • cross-platform: Dieser Wert wird häufig bei der Registrierung von mehrstufigen Anmeldedaten verwendet und nicht im Kontext eines Passkeys.
  • Kein Wert: Damit Nutzer Passkeys auf ihren bevorzugten Geräten erstellen können (z. B. in den Kontoeinstellungen), sollte der Parameter authenticatorAttachment nicht angegeben werden, wenn ein Nutzer einen Passkey hinzufügen möchte. In den meisten Fällen ist es am besten, den Parameter nicht anzugeben.

Erstellen von Passkeys duplizieren verhindern

Geben Sie Anmeldedaten-IDs in dem optionalen excludeCredentials-Array an, um das Erstellen eines neuen Passkeys zu verhindern, wenn bereits einer mit demselben Passkey-Anbieter vorhanden ist.

JSON-Antwort verarbeiten

Das folgende Code-Snippet zeigt eine Beispiel-JSON-Antwort zum Erstellen von Anmeldedaten für öffentliche Schlüssel. Weitere Informationen zum Umgang mit den zurückgegebenen Public-Key-Anmeldedaten

{
  "id": "KEDetxZcUfinhVi6Za5nZQ",
  "type": "public-key",
  "rawId": "KEDetxZcUfinhVi6Za5nZQ",
  "response": {
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibmhrUVhmRTU5SmI5N1Z5eU5Ka3ZEaVh1Y01Fdmx0ZHV2Y3JEbUdyT0RIWSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
    "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUj5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGRdAAAAAAAAAAAAAAAAAAAAAAAAAAAAEChA3rcWXFH4p4VYumWuZ2WlAQIDJiABIVgg4RqZaJyaC24Pf4tT-8ONIZ5_Elddf3dNotGOx81jj3siWCAWXS6Lz70hvC2g8hwoLllOwlsbYatNkO2uYFO-eJID6A"
  }
}

Ursprung aus Clientdaten-JSON prüfen

Das origin steht für die Anwendung oder Website, von der eine Anfrage stammt, und wird von Passkeys zum Schutz vor Phishing-Angriffen verwendet. Der Server Ihrer App muss den Ursprung der Clientdaten mit einer Zulassungsliste genehmigter Apps und Websites abgleichen. Wenn der Server eine Anfrage von einer App oder Website von einem nicht erkannten Ursprung erhält, sollte die Anfrage abgelehnt werden.

Im Web entspricht origin dem Ursprung auf derselben Website, auf der die Anmeldedaten verwendet wurden. Bei der URL https://www.example.com:8443/store?category=shoes#athletic ist origin beispielsweise https://www.example.com:8443.

Bei Android-Apps wird origin vom User-Agent automatisch auf die Signatur der aufrufenden App gesetzt. Diese Signatur muss auf Ihrem Server mit der Signatur abgeglichen werden, um den Aufrufer der Passkey API zu validieren. Der origin von Android ist ein URI, der vom SHA-256-Hash des APK-Signaturzertifikats abgeleitet ist. Beispiel:

android:apk-key-hash:<sha256_hash-of-apk-signing-cert>

Die SHA-256-Hashes der Signaturzertifikate aus einem Schlüsselspeicher können mit dem folgenden Terminalbefehl ermittelt werden:

keytool -list -keystore <path-to-apk-signing-keystore>

Die SHA-256-Hashes sind im hexadezimalen Format mit Doppelpunkten (91:F7:CB:F9:D6:81…) und die Android-origin-Werte sind base64url-codiert. In diesem Python-Beispiel wird gezeigt, wie das Hash-Format in ein kompatibles, durch Doppelpunkte getrenntes Hexadezimalformat umgewandelt wird:

import binascii
import base64
fingerprint = '91:F7:CB:F9:D6:81:53:1B:C7:A5:8F:B8:33:CC:A1:4D:AB:ED:E5:09:C5'
print("android:apk-key-hash:" + base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))

Ersetzen Sie den Wert für fingerprint durch Ihren eigenen Wert. Hier ein Beispiel für ein Ergebnis:

android:apk-key-hash:kffL-daBUxvHpY-4M8yhTavt5QnFEI2LsexohxrGPYU

Sie können diesen String dann als zulässigen Ursprung auf Ihrem Server abgleichen. Wenn Sie mehrere Signaturzertifikate haben, z. B. Zertifikate für die Fehlerbehebung und Veröffentlichung, oder mehrere Apps, wiederholen Sie den Vorgang und akzeptieren Sie alle diese Ursprünge auf dem Server als gültig.

Passwort eines Nutzers speichern

Wenn der Nutzer einen Nutzernamen und ein Passwort für einen Authentifizierungsablauf in Ihrer App angibt, können Sie Nutzeranmeldedaten registrieren, mit denen sich der Nutzer authentifizieren kann. Erstellen Sie dazu ein CreatePasswordRequest-Objekt:

Kotlin

fun registerPassword(username: String, password: String) {
    // Initialize a CreatePasswordRequest object.
    val createPasswordRequest =
            CreatePasswordRequest(id = username, password = password)

    // Create credential and handle result.
    coroutineScope.launch {
        try {
            val result =
                credentialManager.createCredential(
                    // Use an activity based context to avoid undefined
                    // system UI launching behavior.
                    activityContext,
                    createPasswordRequest
                  )
            handleRegisterPasswordResult(result)
        } catch (e: CreateCredentialException) {
            handleFailure(e)
        }
    }
}

Java

void registerPassword(String username, String password) {
    // Initialize a CreatePasswordRequest object.
    CreatePasswordRequest createPasswordRequest =
        new CreatePasswordRequest(username, password);

    // Register the username and password.
    credentialManager.createCredentialAsync(
        // Use an activity-based context to avoid undefined
        // system UI launching behavior
        requireActivity(),
        createPasswordRequest,
        cancellationSignal,
        executor,
        new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() {
            @Override
            public void onResult(CreateCredentialResponse result) {
                handleResult(result);
            }

            @Override
            public void onError(CreateCredentialException e) {
                handleFailure(e);
            }
        }
    );
}

Wiederherstellung von Anmeldedaten unterstützen

Wenn ein Nutzer keinen Zugriff mehr auf ein Gerät hat, auf dem er seine Anmeldedaten gespeichert hat, muss er möglicherweise eine Wiederherstellung aus einer sicheren Onlinesicherung durchführen. Weitere Informationen zur Unterstützung dieses Prozesses zur Wiederherstellung von Anmeldedaten finden Sie im Blogpost Sicherheit von Passkeys im Google Passwortmanager im Abschnitt „Zugriff wiederherstellen oder neue Geräte hinzufügen“.

Unterstützung für Passwortmanager mit bekannten URLs für Passkey-Endpunkte hinzufügen

Für eine nahtlose Integration und zukünftige Kompatibilität mit Tools zur Passwort- und Anmeldedatenverwaltung empfehlen wir, die Unterstützung für bekannte URLs für Passkey-Endpunkte hinzuzufügen. Dies ist ein offenes Protokoll, mit dem Partner ihre Unterstützung für Passkeys offiziell bekannt geben und direkte Links zur Registrierung und Verwaltung von Passkeys bereitstellen können.

  1. Für eine vertrauende Seite bei https://example.com, die eine Website sowie Android- und iOS-Apps hat, lautet die bekannte URL https://example.com/.well-known/passkey-endpoints.
  2. Bei der Abfrage der URL sollte die Antwort das folgende Schema verwenden:

    {
      "enroll": "https://example.com/account/manage/passkeys/create"
      "manage": "https://example.com/account/manage/passkeys"
    }
    
  3. Wenn dieser Link direkt in Ihrer App und nicht im Web geöffnet werden soll, verwenden Sie Android-App-Links.

  4. Weitere Informationen finden Sie in der Erklärung zur bekannten URL für Passkey-Endpunkte auf GitHub.

Nutzern helfen, ihre Passkeys zu verwalten, indem angezeigt wird, welcher Anbieter sie erstellt hat

Eine Herausforderung für Nutzer beim Verwalten mehrerer Passkeys, die mit einer bestimmten App verknüpft sind, besteht darin, den richtigen Passkey für die Bearbeitung oder Löschung zu ermitteln. Zur Behebung dieses Problems empfehlen wir, in Apps und Websites zusätzliche Informationen anzugeben, z. B. den Anbieter, der die Anmeldedaten erstellt hat, das Erstellungsdatum und das Datum der letzten Verwendung in einer Passkey-Liste auf dem Einstellungsbildschirm Ihrer App. Die Anbieterinformationen finden Sie in der AAGUID, die mit dem entsprechenden Passkey verknüpft ist. Die AAGUID ist Teil der Authenticator-Daten eines Passkeys.

Wenn ein Nutzer beispielsweise auf einem Android-Gerät mit dem Google Passwortmanager einen Passkey erstellt, erhält der RP eine AAGUID, die in etwa so aussieht: „ea9b8d66-4d01-1d21-3ce4-b6b48cb575d4“. Die vertrauende Partei kann den Passkey in der Passkey-Liste annotieren, um anzugeben, dass er mit dem Google Passwortmanager erstellt wurde.

Um eine AAGUID einem Passkey-Anbieter zuzuordnen, können RPs ein von der Community bereitgestelltes Repository mit AAGUIDs verwenden. Suchen Sie in dieser Liste nach der AAGUID, um den Namen und das Symbol des Passkey-Anbieters zu finden.

Weitere Informationen zur AAGUID-Integration

Häufige Fehler beheben

Informationen zu häufigen Fehlercodes, Beschreibungen und Ursachen finden Sie im Leitfaden zur Fehlerbehebung für den Anmeldedaten-Manager.

Weitere Informationen

Weitere Informationen zur Credential Manager API und zu Passkeys finden Sie in den folgenden Ressourcen: