Se connecter avec une clé d'accès

Ce guide poursuit l'implémentation de l'utilisation des clés d'accès pour l'authentification. Avant que vos utilisateurs puissent se connecter avec des clés d'accès, vous devez également suivre les instructions de la section Créer des clés d'accès.

Pour vous authentifier avec une clé d'accès, vous devez d'abord récupérer les options nécessaires pour récupérer la clé publique depuis votre serveur d'application, puis appeler l'API Credential Manager pour récupérer la clé publique. Gérez ensuite la réponse de connexion de manière appropriée.

Présentation

Ce guide se concentre sur les modifications requises dans votre application cliente pour permettre à votre utilisateur de se connecter avec une clé d'accès. Il fournit également un bref aperçu de l'implémentation côté serveur de l'application. Pour en savoir plus sur l'intégration côté serveur, consultez Authentification par clé d'accès côté serveur.

Pour récupérer toutes les clés d'accès et options de mots de passe associées au compte de l'utilisateur, procédez comme suit :

  1. Obtenir les options de demande d'identifiants auprès du serveur : envoyez une requête depuis votre application vers votre serveur d'authentification pour démarrer le processus de connexion avec une clé d'accès. À partir du serveur, envoyez les options requises pour obtenir l'identifiant de clé publique, ainsi qu'un défi unique.
  2. Créez l'objet requis pour obtenir l'identifiant de clé publique : encapsulez les options envoyées par le serveur dans un objet GetPublicKeyCredentialOption.
  3. (Facultatif) Préparer getCredential : sur Android 14 et versions ultérieures, vous pouvez réduire la latence en affichant le sélecteur de compte à l'aide de la méthode prepareGetCredential() avant d'appeler getCredential().
  4. Lancer le flux de connexion : appelez la méthode getCredential() pour connecter l'utilisateur.
  5. Gérer la réponse : gérez chacune des réponses d'identifiants possibles.
  6. Gérer les exceptions : assurez-vous de gérer les exceptions de manière appropriée.

1. Obtenir les options de demande d'identifiants à partir du serveur

Demandez au serveur les options requises pour obtenir les identifiants de clé publique, ainsi que le challenge, qui est unique pour chaque tentative de connexion. Pour en savoir plus sur l'implémentation côté serveur, consultez Créer le challenge et Créer des options de demande d'identifiant.

Les options ressemblent à ce qui suit :

{
  "challenge": "<your app challenge>",
  "allowCredentials": [],
  "rpId": "<your app server domain>"
}

Pour en savoir plus sur les champs, consultez l'article de blog sur la connexion avec une clé d'accès.

2. Créez l'objet requis pour obtenir les identifiants de clé publique.

Dans votre application, utilisez les options pour créer un objet GetPublicKeyCredentialOption. Dans l'exemple suivant, requestJson représente les options envoyées par le serveur.

// Get password logins from the credential provider on the user's device.
val getPasswordOption = GetPasswordOption()

// Get passkeys from the credential provider on the user's device.
val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
    requestJson = requestJson
)

Ensuite, encapsulez GetPublicKeyCredentialOption dans un objet GetCredentialRequest.

val credentialRequest = GetCredentialRequest(
    // Include all the sign-in options that your app supports.
    listOf(getPasswordOption, getPublicKeyCredentialOption),
    // Defines whether you prefer to use only immediately available
    // credentials or hybrid credentials.
    preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
)

3. Facultatif : Réduire la latence de connexion

Sur Android 14 ou version ultérieure, vous pouvez réduire la latence lorsque vous affichez le sélecteur de compte à l'aide de la méthode prepareGetCredential() avant d'appeler getCredential().

La méthode prepareGetCredential() renvoie un objet PrepareGetCredentialResponse mis en cache. Cela permet à la méthode getCredential() de l'étape suivante d'afficher le sélecteur de compte avec les données mises en cache.

coroutineScope {
    val response = credentialManager.prepareGetCredential(
        GetCredentialRequest(
            listOf(
                // Include all the sign-in options that your app supports
                getPublicKeyCredentialOption, 
                getPasswordOption
            )
        )
    )
}

4. Lancer le flux de connexion

Appelez la méthode getCredential() pour afficher le sélecteur de compte à l'utilisateur. Utilisez l'extrait de code suivant comme référence pour lancer le flux de connexion :

coroutineScope {
    try {
        result = credentialManager.getCredential(
            // Use an activity-based context to avoid undefined system UI
            // launching behavior.
            context = activityContext,
            request = credentialRequest
        )
        handleSignIn(result)
    } catch (e: GetCredentialException) {
        // Handle failure
    }
}

5. Gérer la réponse

Gérez la réponse, qui peut contenir l'un des différents types d'objets d'identifiants.

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")
        }
    }
}

Le PublicKeyCredential renvoyé par l'authentification est essentiellement une assertion signée, structurée comme suit :

{
  "id": "<credential ID>",
  "type": "public-key",
  "rawId": "<raw credential ID>",
  "response": {
    "clientDataJSON": "<signed client data containing challenge>",
    "authenticatorData": "<authenticator metadata>",
    "signature": "<digital signature to be verified>",
    "userHandle": "<user ID from credential registration>"
  }
}

Sur le serveur, vous devez valider l'identifiant. Pour en savoir plus, consultez Valider l'utilisateur et se connecter.

6. Gérer les exceptions

Vous devez gérer toutes les exceptions de sous-classe de GetCredentialException. Pour savoir comment gérer chaque exception, consultez le guide de dépannage.

coroutineScope {
    try {
        result = credentialManager.getCredential(
            context = activityContext,
            request = credentialRequest
        )
    } catch (e: GetCredentialException) {
        Log.e("CredentialManager", "No credential available", e)
    }
}

Étapes suivantes