Créer une clé d'accès

Avant que vos utilisateurs puissent s'authentifier avec des clés d'accès, votre application doit d'abord enregistrer ou créer la clé d'accès pour leur compte.

Pour créer la clé d'accès, obtenez les informations requises auprès du serveur de votre application, puis appelez l'API Credential Manager, qui renvoie une paire de clés publique et privée. La clé privée renvoyée est stockée dans un fournisseur d'identifiants, tel que le Gestionnaire de mots de passe de Google, sous forme de clé d'accès. La clé publique est stockée sur le serveur de votre application.

Les clés d'accès sont stockées dans un fournisseur d'identifiants et les clés publiques sont stockées sur le serveur de l'application.
Figure 1 : Création de clés d'accès

Prérequis

Assurez-vous d'avoir configuré les Digital Asset Links et de cibler les appareils exécutant Android 9 (niveau d'API 28) ou une version ultérieure.

Présentation

Ce guide se concentre sur les modifications requises dans l'application cliente de votre partie de confiance pour créer une clé d'accès. Il fournit également une brève présentation de l'implémentation du serveur d'application de la partie de confiance. Pour en savoir plus sur l'intégration côté serveur, consultez la section Enregistrement des clés d'accès côté serveur.

  1. Ajouter des dépendances à votre application : ajoutez les bibliothèques requises du Gestionnaire d'identifiants.
  2. Instancier Credential Manager : créez une instance de Credential Manager.
  3. Obtenir les options de création d'identifiants à partir du serveur d'application : à partir du serveur de votre application, envoyez à l'application cliente les informations requises pour créer la clé d'accès, telles que des informations sur l'application, l'utilisateur, ainsi qu'un challenge et d'autres champs.
  4. Demander une clé d'accès : dans votre application, utilisez les informations reçues du serveur d'application pour créer un objet GetPublicKeyCredentialOption et utilisez cet objet pour appeler la méthode credentialManager.getCredential() afin de créer une clé d'accès.
  5. Gérer la réponse de création de la clé d'accès : lorsque vous recevez les identifiants sur votre application cliente, vous devez les encoder, les sérialiser, puis envoyer la clé publique au serveur d'application. Vous devez également gérer chacune des exceptions qui peuvent se produire en cas de création de clé d'accès.
  6. Vérifier et enregistrer la clé publique sur le serveur : suivez les étapes côté serveur pour vérifier l'origine de l'identifiant, puis enregistrez la clé publique.
  7. Informer l'utilisateur : informez l'utilisateur que sa clé d'accès a été créée.

Ajouter des dépendances à votre application

Ajoutez les dépendances suivantes au fichier build.gradle du module de votre application :

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.7.0-alpha02")
    implementation("androidx.credentials:credentials-play-services-auth:1.7.0-alpha02")
}

Groovy

dependencies {
    implementation "androidx.credentials:credentials:1.7.0-alpha02"
    implementation "androidx.credentials:credentials-play-services-auth:1.7.0-alpha02"
}

Instancier le Gestionnaire d'identifiants

Utilisez le contexte de votre application ou de votre activité pour créer un objet CredentialManager.

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

Obtenir les options de création d'identifiants à partir du serveur de votre application

Lorsque l'utilisateur clique sur le bouton "Créer une clé d'accès" ou lorsqu'un nouvel utilisateur s'inscrit, envoyez une requête de votre application au serveur de votre application pour obtenir les informations requises pour démarrer le processus d'enregistrement de la clé d'accès.

Utilisez une bibliothèque compatible avec FIDO sur le serveur de votre application pour envoyer à votre application cliente les informations requises pour créer une clé d'accès, telles que des informations sur l'utilisateur, l'application et des propriétés de configuration supplémentaires. Pour en savoir plus, consultez la section Enregistrement des clés d'accès côté serveur.

Dans l'application cliente, décodez les options de création de clé publique envoyées par le serveur d'application. Elles sont généralement représentées au format JSON. Pour en savoir plus sur le décodage pour les clients Web, consultez la section Encodage et décodage. Pour les applications clientes Android, vous devez gérer le décodage séparément.

L'extrait de code suivant montre la structure des options de création de clé publique envoyées par le serveur d'application :

{
  "challenge": "<base64url-encoded challenge>",
  "rp": {
    "name": "<relying party name>",
    "id": "<relying party host name>"
  },
  "user": {
    "id": "<base64url-encoded user ID>",
    "name": "<user name>",
    "displayName": "<user display name>"
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    }
  ],
  "attestation": "none",
  "excludeCredentials": [
    {
        "id": "<base64url-encoded credential ID to exclude>", 
        "type": "public-key"
    }
  ],
  "authenticatorSelection": {
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

Les champs clés des options de création de clé publique incluent les éléments suivants :

  • challenge: chaîne aléatoire générée par le serveur qui permet d'éviter les attaques par relecture.
  • rp: détails sur l'application.
    • rp.name : nom de l'application.
    • rp.id : domaine ou sous-domaine de l'application.
  • user : détails sur l'utilisateur.
    • id : ID unique de l'utilisateur. Cette valeur ne doit contenir aucune information permettant d'identifier personnellement l'utilisateur, comme une adresse e-mail ou un nom d'utilisateur. Vous pouvez utiliser une valeur aléatoire de 16 octets.
    • name: identifiant unique du compte que l'utilisateur reconnaîtra, tel que son adresse e-mail ou son nom d'utilisateur. Cet identifiant apparaîtra dans le sélecteur de comptes. Si vous utilisez un nom d'utilisateur, spécifiez la même valeur que pour l'authentification par mot de passe.
    • displayName: nom facultatif et convivial du compte destiné à s'afficher dans le sélecteur de comptes.
  • authenticatorSelection: détails sur l'appareil qui sera utilisé pour l'authentification.
    • authenticatorAttachment : indique l'authentificateur préféré . Les valeurs possibles sont les suivantes :
      • platform: cette valeur est utilisée pour un authentificateur intégré à l'appareil de l'utilisateur, tel qu'un lecteur d'empreinte digitale.
      • cross-platform: cette valeur est utilisée pour les appareils itinérants tels que les clés de sécurité. Elle n'est généralement pas utilisée dans le contexte des clés d'accès.
      • Non spécifié (recommandé) : si vous ne spécifiez pas cette valeur, les utilisateurs peuvent créer des clés d'accès sur les appareils de leur choix. Dans la plupart des cas, il est préférable de ne pas spécifier le paramètre.
    • requireResidentKey: pour créer une clé d'accès, définissez la valeur de ce champ Boolean sur true.
    • residentKey : pour créer une clé d'accès, définissez la valeur sur required.
    • userVerification: permet de spécifier les exigences de validation de l'utilisateur lors de l'enregistrement d'une clé d'accès. Les valeurs possibles sont les suivantes :
      • preferred: utilisez cette valeur si vous privilégiez l'expérience utilisateur à la protection, par exemple dans les environnements où la validation de l'utilisateur génère plus de friction que de protection.
      • required: utilisez cette valeur si l'appel d'une méthode de validation de l'utilisateur disponible sur l'appareil est obligatoire.
      • discouraged: utilisez cette valeur si l'utilisation d'une méthode de validation de l'utilisateur est déconseillée.
        Pour en savoir plus sur userVerification, consultez la section Analyse approfondie de userVerification.
  • excludeCredentials : répertoriez les ID d'identifiants dans un tableau pour empêcher la création d'une clé d'accès en double s'il en existe déjà une avec le même fournisseur d'identifiants.

Créer une clé d'accès

Après avoir analysé les options de création de clé publique côté serveur, créez une clé d'accès en encapsulant ces options dans un objet CreatePublicKeyCredentialRequest et en appelant createCredential().

createPublicKeyCredentialRequest inclut les éléments suivants :

  • requestJson : options de création d'identifiants envoyées par le serveur d'application.
  • preferImmediatelyAvailableCredentials : champ booléen facultatif qui indique si vous préférez n'utiliser que des identifiants disponibles localement ou synchronisés avec le fournisseur d'identifiants pour traiter la requête, plutôt que des identifiants de clés de sécurité ou de flux de clés hybrides. Les utilisations possibles sont les suivantes :
    • false (par défaut) : utilisez cette valeur si l'appel au Gestionnaire d'identifiants a été déclenché par une action explicite de l'utilisateur.
    • true : utilisez cette valeur si le Credential Manager est appelé de manière opportuniste , par exemple lors de la première ouverture de l'application.
      Si vous définissez la valeur sur true et qu'aucun identifiant n'est disponible immédiatement, le Credential Manager n'affiche aucune UI et la requête échoue immédiatement et renvoie NoCredentialException pour les requêtes GET et CreateCredentialNoCreateOptionException pour les requêtes de création.
  • origin : ce champ est automatiquement défini pour les applications Android. Pour les navigateurs et les applications privilégiées similaires qui doivent définir origin, consultez la section Passer des appels du Gestionnaire d'identifiants au nom d'autres parties pour des applications privilégiées.
  • isConditional : champ facultatif dont la valeur par défaut est false. Pour en savoir plus, consultez la section Créer automatiquement une clé d'accès.

L'appel de la fonction createCredential() lance l'UI bottom sheet intégrée du Gestionnaire d'identifiants, qui invite l'utilisateur à utiliser une clé d'accès et à sélectionner un fournisseur d'identifiants et un compte pour le stockage. Toutefois, si isConditional est défini sur true, l'UI bottom sheet ne s'affiche pas et la clé d'accès est créée automatiquement.

Créer automatiquement une clé d'accès

Vous pouvez créer automatiquement une clé d'accès pour un utilisateur après une connexion réussie par mot de passe en définissant le paramètre isConditional sur true dans votre CreatePublicKeyCredentialRequest lors de la création d'une clé d'accès. Si l'utilisateur ne dispose pas encore d'une clé d'accès, votre application tente automatiquement d'en créer une en arrière-plan et de la stocker dans le fournisseur d'identifiants de l'utilisateur, tel que le Gestionnaire de mots de passe de Google. Pour obtenir un exemple d'implémentation, consultez l'exemple public.

Exemple de notification affichée par le Gestionnaire de mots de passe de Google après la création d&#39;une clé d&#39;accès
Figure 2 : Notification du Gestionnaire de mots de passe de Google

Gérer la réponse

Une fois l'utilisateur validé à l'aide du verrouillage de l'écran de l'appareil, une clé d'accès est créée et stockée dans le fournisseur d'identifiants sélectionné par l'utilisateur.

La réponse après l'appel réussi de createCredential() est un objet PublicKeyCredential.

L'objet PublicKeyCredential se présente comme suit :

{
  "id": "<identifier>",
  "type": "public-key",
  "rawId": "<identifier>",
  "response": {
    "clientDataJSON": "<ArrayBuffer encoded object with the origin and signed challenge>",
    "attestationObject": "<ArrayBuffer encoded object with the public key and other information.>"
  },
  "authenticatorAttachment": "platform"
}

Dans l'application cliente, sérialisez l'objet et envoyez-le au serveur d'application.

Ajoutez du code pour gérer les échecs, comme indiqué dans l'extrait de code suivant :

fun handleFailure(e: CreateCredentialException) {
    when (e) {
        is CreatePublicKeyCredentialDomException -> {
            // Handle the passkey DOM errors thrown according to the
            // WebAuthn spec.
        }
        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 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}")
    }
}

Vérifier et enregistrer la clé publique sur le serveur d'application

Sur le serveur d'application, vous devez vérifier l'identifiant de clé publique, puis enregistrer la clé publique.

Pour vérifier l'origine de l'identifiant de clé publique, comparez-le à une liste d'autorisation d'applications approuvées. Si une clé a une origine non reconnue, rejetez-la.

Pour obtenir l'empreinte SHA-256 de l'application :

  1. Imprimez le certificat de signature de votre application de publication en exécutant la commande suivante dans un terminal :

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

    Dans la réponse, identifiez l'empreinte SHA-256 du certificat de signature, mentionnée comme Certificate fingerprints block : SHA256.

  2. Encodez l'empreinte SHA-256 avec l'encodage base64url. Cet exemple Python montre comment encoder correctement l'empreinte :

    import binascii
    import base64
    fingerprint = '<SHA256 finerprint>' # your app's SHA256 fingerprint
    print(base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))
    
  3. Ajoutez android:apk-key-hash: au début de la sortie de l'étape précédente pour obtenir un résultat semblable à celui-ci :

    android:apk-key-hash:<encoded SHA 256 fingerprint>
    

    Le résultat doit correspondre à une origine autorisée sur le serveur de votre application. Si vous disposez de plusieurs certificats de signature, tels que des certificats de débogage et de publication, ou de plusieurs applications, répétez le processus et acceptez toutes les origines comme valides sur le serveur d'application.

Informer l'utilisateur

Une fois la clé d'accès créée, informez vos utilisateurs de son existence et indiquez-leur qu'ils peuvent la gérer depuis l'application de leur fournisseur d'identifiants ou depuis les paramètres de l'application. Informez les utilisateurs à l'aide d'une boîte de dialogue personnalisée, d'une notification ou d'une barre de notification. Étant donné qu'une création inattendue de clé d'accès par une entité malveillante nécessite une alerte de sécurité immédiate, envisagez de compléter ces méthodes intégrées à l'application par une communication externe, telle qu'un e-mail.

Améliorer l'expérience utilisateur

Pour améliorer l'expérience utilisateur lors de l'implémentation de l'inscription avec le Gestionnaire d'identifiants, envisagez d'ajouter une fonctionnalité permettant de restaurer les identifiants et de supprimer les boîtes de dialogue de saisie automatique.

Ajouter une fonctionnalité permettant de restaurer les identifiants sur un nouvel appareil

Pour permettre aux utilisateurs de se connecter facilement à leurs comptes sur un nouvel appareil, implémentez la fonctionnalité de restauration des identifiants. L'ajout de la restauration des identifiants avec BackupAgent connecte les utilisateurs lorsqu'ils ouvrent votre application restaurée sur un nouvel appareil, ce qui leur permet de l'utiliser immédiatement.

Supprimer la saisie automatique dans les champs d'identifiants (facultatif)

Pour les écrans d'application où les utilisateurs sont censés utiliser l'UI bottom sheet du Gestionnaire d'identifiants pour l'authentification, ajoutez l'attribut isCredential aux champs de nom d'utilisateur et de mot de passe. Cela empêche les boîtes de dialogue de saisie automatique (FillDialog et SaveDialog) de se chevaucher avec l'UI bottom sheet du Gestionnaire d'identifiants.

L'attribut isCredential est compatible avec Android 14 et versions ultérieures.

L'exemple suivant montre comment ajouter l'attribut isCredential aux champs de nom d'utilisateur et de mot de passe pertinents dans les vues correspondantes de votre application :

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

Étapes suivantes