Cette page explique comment créer une clé de restauration, comment l'utiliser pour se connecter et comment la supprimer.
Compétences Android
Afficher sur GitHubRestaurer les identifiants
android skills add restore-credentialsCompatibilité des versions
La fonctionnalité Restore Credentials de Credential Manager fonctionne sur les appareils équipés d'Android 9 (niveau d'API 28) ou version ultérieure, de la version principale 242200000 (v24.22) ou ultérieure des services Google Play (GMS) et de la version 1.5.0 ou ultérieure de la bibliothèque androidx.credentials. Sur les appareils sans services Google Play ou avec une ancienne version de GMS, interceptez CreateCredentialProviderConfigurationException et GetCredentialProviderConfigurationException pour que votre application revienne correctement à la connexion standard.
Prérequis
Configurez un serveur de tiers de confiance WebAuthn semblable au serveur pour les clés d'accès. Si vous avez déjà configuré un serveur pour gérer l'authentification avec des clés d'accès, vous pouvez réutiliser les mêmes points de terminaison d'enregistrement et d'assertion WebAuthn pour les clés de restauration.
Dépendances
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" }
Restore Credentials est disponible à partir de la version 1.5.0 de la bibliothèque androidx.credentials. Toutefois, il est recommandé d'utiliser les dernières versions stables des dépendances dans la mesure du possible.
Impact de android:allowBackup sur la restauration des identifiants
L'attribut de fichier manifeste android:allowBackup contrôle la sauvegarde des données de l'application, qui interagit avec Restore Credentials de trois manières différentes :
- Transfert de clé de restauration (indépendant de
allowBackup) : les services Google Play transfèrent la paire de clésRestoreCredentialà l'aide d'une sauvegarde cloud chiffrée de bout en bout ou d'un transfert local d'appareil à appareil (D2D), queandroid:allowBackupsoit défini surtrueoufalse. Pour les transferts d'appareil à appareil, la clé de restauration est toujours transférée. La seule condition dans laquelle elle n'est pas transférée est lors d'une sauvegarde cloud lorsque l'utilisateur a désactivé la sauvegarde cloud dans les paramètres Android. - Restauration en arrière-plan dans
BackupAgent(nécessiteandroid:allowBackup="true") : la connexion silencieuse en arrière-plan avant que l'utilisateur n'ouvre l'application sur le nouvel appareil (BackupAgent.onRestoreFinished()) ne s'exécute que lorsqueandroid:allowBackup="true"etandroid:backupAgentsont configurés dans votre fichier manifeste. Si la valeur estandroid:allowBackup="false", restaurez la session lorsque l'utilisateur lance votreActivityprincipal pour la première fois. Vous pouvez également mettre en œuvre les deux approches pour rendre la restauration plus robuste. - Tests de sauvegarde cloud Android Studio (nécessite
android:allowBackup="true") : pour tester le type de sauvegarde Cloud dans l'outil de sauvegarde et de restauration d'Android Studio, vous devez disposer deandroid:allowBackup="true", tandis que les tests Appareil à appareil fonctionnent indépendamment deallowBackup.
Présentation
L'API Restore Credentials suit un cycle de vie en trois étapes sur l'ancien et le nouvel appareil de l'utilisateur :
- Créer une clé de restauration sur l'appareil précédent : une fois que l'utilisateur s'est connecté (ou au démarrage de l'application s'il est déjà connecté et qu'aucune clé de restauration n'est enregistrée dans l'espace de stockage local), récupérez les options de création à partir de votre serveur de tiers de confiance et appelez
credentialManager.createCredential(). - Se connecter avec la clé de restauration sur le nouvel appareil : récupérez la clé
RestoreCredentialtransférée à l'aide d'une stratégie à deux niveaux : d'abord en arrière-plan dansBackupAgent.onRestoreFinished()(lorsqueandroid:allowBackup="true") pour que la synchronisation en arrière-plan et les notifications push reprennent immédiatement, puis en tant que solution de secours dans votre lanceur d'applicationsActivity.onCreate()lors du premier lancement de l'application. - Supprimer la clé de restauration lors de la déconnexion : lorsque l'utilisateur se déconnecte ou que sa session est invalidée par le serveur, appelez
credentialManager.clearCredentialState()avecClearCredentialStateRequest(ClearCredentialStateRequest.TYPE_CLEAR_RESTORE_CREDENTIAL)et effacez votre indicateur de synchronisation locale.
Créer une clé de restauration
Votre application doit couvrir tous les cas de connexion d'un utilisateur pour s'assurer que les utilisateurs actifs disposent d'une clé de restauration. Créez la clé de restauration dans les scénarios suivants :
- Si l'utilisateur est connecté et qu'une clé de restauration n'a pas encore été créée (par exemple, dans la méthode
onCreate()pour l'Activityprincipal). - Lorsque l'utilisateur se connecte ou termine le processus d'enregistrement d'un nouveau compte.
Pour éviter d'appeler createCredential() à chaque lancement de l'application, stockez un indicateur de synchronisation locale tel que has_synced_restore_credential dans l'espace de stockage local. Ne stockez pas cette option dans les fichiers SharedPreferences ou DataStore sauvegardés par défaut, sauf si ce fichier est exclu dans data_extraction_rules.xml. Sinon, la sauvegarde automatique copie has_synced_restore_credential = true sur le nouvel appareil et l'empêche de générer ou de faire pivoter sa propre clé de restauration.
Instancier Credential Manager
Utilisez le contexte d'activité de votre application pour instancier 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
Utilisez une bibliothèque compatible avec FIDO sur votre serveur d'application pour envoyer à votre application cliente le fichier JSON PublicKeyCredentialCreationOptions requis pour créer l'identifiant de restauration. Pour en savoir plus sur l'implémentation côté serveur, consultez Conseils côté serveur.
Le fichier JSON des options de création suit la même structure que l'enregistrement de la clé d'accès :
{
"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"
}
}
Assurez-vous que le fichier JSON des options de création répond aux exigences suivantes :
challengeetuser.id: encodez les deux valeurs sous forme de chaînes Base64URL sans marge (en remplaçant+par-,/par_et en supprimant le caractère=de fin). Les caractères Base64 standards ou les ID d'entiers bruts entraînent une erreurCreateRestoreCredentialDomExceptionouIllegalArgumentException.rp.id: définissez cette valeur sur le domaine de votre partie de confiance (par exemple,example.com).pubKeyCredParams: incluez{"type": "public-key", "alg": -7}(ES256) et{"type": "public-key", "alg": -257}(RS256).
Créer la clé de restauration
Après avoir reçu le fichier JSON des options de création de clé publique de votre serveur, encapsulez-le dans un objet CreateRestoreCredentialRequest et appelez createCredential() sur l'objet CredentialManager.
// createRestoreRequest contains the details sent by the server
val response = credentialManager.createCredential(context, createRestoreRequest)
Points clés concernant le code
L'objet
CreateRestoreCredentialRequestcontient les champs suivants :requestJson: options de création d'identifiants envoyées par le serveur d'applications au format de l'API Web Authentication pourPublicKeyCredentialCreationOptionsJSON.isCloudBackupEnabled: champBooleanpermettant de déterminer si la clé de restauration doit être sauvegardée dans le cloud. Par défaut, cette option est définie surtrue. Ce champ accepte les valeurs suivantes :true: (recommandé) cette valeur permet de sauvegarder les clés de restauration dans le cloud si l'utilisateur a activé la sauvegarde Google et le chiffrement de bout en bout, comme un verrouillage de l'écran.false: cette valeur enregistre la clé localement et non dans le cloud. La clé n'est pas disponible sur le nouvel appareil si l'utilisateur choisit de restaurer les données depuis le cloud, mais elle est toujours transférée lors d'une configuration locale d'appareil à appareil (D2D) par câble ou Wi-Fi.
Gérer la réponse de création d'identifiants
L'API Credential Manager renvoie une réponse de type CreateRestoreCredentialResponse. Cette réponse contient la réponse d'enregistrement des identifiants de clé publique au format JSON.
Envoyez response.registrationResponseJson de votre application à votre serveur de tiers de confiance pour valider et stocker la clé publique avec le compte de l'utilisateur, puis enregistrez votre repère de synchronisation locale dans l'espace de stockage local. Pour en savoir plus sur la validation côté serveur, consultez les conseils pour les clés d'accès.
Lors du processus de création de la clé de restauration, gérez les exceptions suivantes :
CreateRestoreCredentialDomException: cette exception se produit sirequestJsonn'est pas valide et ne respecte pas le format WebAuthn pourPublicKeyCredentialCreationOptionsJSON.E2eeUnavailableException: cette exception se produit siisCloudBackupEnabledest défini surtrue, mais que l'appareil de l'utilisateur ne dispose pas de sauvegarde des données ni de chiffrement de bout en bout, comme un verrouillage de l'écran.
Pour vous assurer que les identifiants de restauration sont créés pour les transferts locaux d'appareil à appareil (D2D) même lorsque le chiffrement de bout en bout dans le cloud n'est pas disponible, interceptezE2eeUnavailableExceptionet réessayez immédiatementcreateCredential()avecCreateRestoreCredentialRequest(requestJson, isCloudBackupEnabled = false).IllegalArgumentException: cette exception se produit sirequestJsonest vide, n'est pas un JSON valide ou ne comporte pas deuser.idvalide encodé en Base64URL conforme aux spécifications WebAuthn.
Se connecter avec une clé de restauration
Utilisez l'API Restore Credentials pour connecter l'utilisateur de manière silencieuse pendant le processus de configuration de l'appareil.
Obtenir les options de récupération des identifiants auprès du serveur d'application
Avant d'appeler getCredential() sur le nouvel appareil, demandez une question d'authentification JSON WebAuthn PublicKeyCredentialRequestOptions à votre serveur d'application. Étant donné que l'application sur le nouvel appareil ne sait pas encore quel utilisateur se connecte, ce point de terminaison doit être non authentifié (découverte sans utilisateur). Pour obtenir des conseils sur le serveur, consultez Se connecter avec une clé d'accès et le guide d'authentification côté serveur.
Le fichier JSON des options de récupération présente la structure suivante :
{
"challenge": "<your app challenge>",
"allowCredentials": [],
"rpId": "<your app server domain>"
}
Configurez le fichier JSON des options de récupération sur votre serveur comme suit :
allowCredentials: omettez ce champ ou transmettez un tableau vide ([]), car le compte de l'utilisateur n'est pas connu avant la restauration. Une fois quegetCredential()est renvoyé, votre serveur identifie l'utilisateur à partir du champresponse.userHandle(qui correspond auuser.idenregistré lors de la création) et recherche la clé publique parid(credentialId).userVerification: défini sur"discouraged"(ou"preferred"). Étant donné que la restauration des identifiants s'exécute de manière silencieuse sans interface utilisateur biométrique ou de verrouillage de l'écran, Android remplace"required"par"discouraged", et les données de l'authentificateur renvoyées à votre serveur ont l'indicateur "Utilisateur validé" (uv) défini surfalse. Configurez le vérificateur de votre serveur WebAuthn pour qu'il accepteuv = falsepour les assertions de clé de restauration.
Obtenir la clé de restauration
Pour obtenir la clé de restauration sur le nouvel appareil, encapsulez le requestJson du serveur dans un GetRestoreCredentialOption à l'intérieur d'un GetCredentialRequest et appelez getCredential() sur l'objet CredentialManager.
Mettez en œuvre une stratégie de restauration à deux niveaux afin que les utilisateurs soient connectés, que la restauration des données de l'application en arrière-plan soit exécutée ou non :
- Niveau 1 (restauration en arrière-plan dans
BackupAgent.onRestoreFinished()) : si la sauvegarde des données de l'application est activée (android:allowBackup="true"), sous-classezBackupAgentet remplacezonRestoreFinished()(n'utilisez pasonRestore(), qui n'est appelé que pour les anciennes sauvegardes clé-valeur). CommeonRestoreFinished()est synchrone et quegetCredential()est une fonctionsuspendKotlin, reliez l'appel à l'aide derunBlocking(Dispatchers.IO). InterceptezNoCredentialExceptionde manière silencieuse lorsqu'aucune clé de restauration n'est présente. - Niveau 2 (solution de secours au premier plan dans le lanceur d'applications
Activity.onCreate()) : lors du premier lancement de l'application, lorsqu'aucune session locale n'existe, appelezgetCredential()depuislifecycleScopeavant d'afficher l'écran de connexion. Cela gère les applications avecandroid:allowBackup="false"et récupère les données si l'appareil était hors connexion lors de l'exécution deonRestoreFinished().
Si vous ajoutez un nouveau BackupAgent à une application qui utilise déjà la sauvegarde automatique avec android:allowBackup="true", définissez également android:fullBackupOnly="true" sur l'élément <application> dans AndroidManifest.xml afin qu'Android continue d'utiliser la sauvegarde automatique au lieu de passer à l'ancienne sauvegarde clé-valeur.
// Fetch the options required to get the restore key
val authenticationJson = fetchAuthenticationJson()
// Create the GetRestoreCredentialRequest object
val options = GetRestoreCredentialOption(authenticationJson)
val getRequest = GetCredentialRequest(listOf(options))
val response = credentialManager.getCredential(context, getRequest)
// Type-check and extract the restore credential
val credential = response.credential as RestoreCredential
L'API Credential Manager renvoie un GetCredentialResponse dont la propriété credential est un RestoreCredential (et non un PublicKeyCredential) contenant authenticationResponseJson.
Gérer la réponse de connexion
Envoyez restoreCredential.authenticationResponseJson de l'application à votre serveur de tiers de confiance pour valider l'assertion cryptographique et émettre un nouveau jeton de session pour l'utilisateur. Pour en savoir plus sur la validation côté serveur, consultez Se connecter avec une clé d'accès.
Lorsque vous concevez votre stockage de backend et vos règles de cycle de vie pour les clés de restauration, suivez ces consignes :
- Différenciez les clés de restauration des clés d'accès utilisateur : ajoutez un tag aux clés de restauration dans votre base de données afin qu'elles soient masquées sur les écrans de gestion des clés d'accès visibles par l'utilisateur et qu'elles ne soient pas soumises aux vérifications de l'utilisateur (
uv = true). - Prise en charge de plusieurs appareils actifs par utilisateur : un utilisateur peut posséder plusieurs appareils (par exemple, un téléphone et une tablette). Autorisez plusieurs clés de restauration actives par compte utilisateur (par exemple, par appareil ou par ID d'installation) au lieu d'écraser une seule ligne.
- Définissez une valeur TTL appropriée et nettoyez les clés orphelines : la désinstallation d'une application ou l'effacement des données de l'application supprime la clé de restauration locale sans en informer votre serveur. Conservez les clés de restauration suffisamment longtemps pour couvrir les périodes de mise à niveau de l'appareil (même si l'utilisateur se déconnecte de l'ancien appareil après le transfert) et supprimez les clés obsolètes en fonction de la valeur TTL d'inactivité ou des limites de clés par utilisateur.
Supprimer la clé de restauration
Credential Manager est sans état et n'est pas au courant de l'activité de l'utilisateur. Il ne supprime donc pas automatiquement les clés de restauration après utilisation. Pour supprimer une clé de restauration, appelez la méthode clearCredentialState(). Pour des raisons de sécurité, supprimez la clé chaque fois qu'un utilisateur se déconnecte afin qu'il ne soit pas reconnecté de manière silencieuse au prochain lancement de l'application.
Les clés de restauration ne sont supprimées que dans les cas suivants :
- Actions au niveau du système : les utilisateurs désinstallent l'application ou effacent ses données.
- Appels au niveau de l'application : supprimez la clé de manière programmatique en appelant
clearCredentialState()lorsque vous gérez la déconnexion de l'utilisateur dans le code de votre application.
Étant donné qu'un ClearCredentialStateRequest() par défaut n'efface que l'état de session standard et laisse la clé de restauration intacte, effectuez un double effacement lors de la déconnexion :
- Appelez
credentialManager.clearCredentialState(ClearCredentialStateRequest())pour effacer l'état de la session du fournisseur d'identifiants actif. - Appelez
credentialManager.clearCredentialState()avecClearCredentialStateRequest(ClearCredentialStateRequest.TYPE_CLEAR_RESTORE_CREDENTIAL)pour supprimer leRestoreCredentialstocké. - Supprimez votre repère
has_synced_restore_credentiallocal de l'espace de stockage local.
// Create a ClearCredentialStateRequest object
val clearRequest = ClearCredentialStateRequest(TYPE_CLEAR_RESTORE_CREDENTIAL)
// When the user logs out, delete the restore key
val response = credentialManager.clearCredentialState(clearRequest)
Étapes suivantes
- Tester Restore Credentials : testez les flux de restauration dans le cloud et d'appareil à appareil (D2D) à l'aide d'Android Studio ou de
adb shell bmgr. - Tests automatisés de sauvegarde et de restauration : écrivez des tests d'hôte JUnit 5 avec
BackupRestoreControllerpour vérifier les restaurationsCLOUD_ENCRYPTEDetDEVICE_TO_DEVICEdans l'intégration continue.