バージョンの互換性
Credential Manager の Restore Credentials は、Android 9(API レベル 28)以降、Google Play 開発者サービス(GMS)コア バージョン 24220000 以降、および androidx.credentials ライブラリ バージョン 1.5.0 以降を搭載したデバイスで動作します。
前提条件
パスキーのサーバーと同様の証明書利用者サーバーをセットアップします。パスキーによる認証を処理するようにサーバーがすでに設定されている場合は、復元キーにも同じサーバーサイド実装を使用します。
依存関係
アプリ モジュールの build.gradle ファイルに次の依存関係を追加します。
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" }
認証情報の復元は、androidx.credentials ライブラリのバージョン 1.5.0 以降で利用できます。ただし、可能な限り、依存関係の最新の安定版を使用することをおすすめします。
概要
- 復元キーを作成する: 復元キーを作成するには、次の手順を行います。
- 認証情報マネージャーをインスタンス化する:
CredentialManagerオブジェクトを作成します。 - アプリサーバーから認証情報作成オプションを取得する: アプリサーバーから復元キーを作成するために必要な詳細情報をクライアント アプリに送信します。
- 復元キーを作成する: ユーザーがアプリにログインしている場合は、ユーザーのアカウントの復元キーを作成します。
- 認証情報作成のレスポンスを処理する: クライアント アプリからアプリサーバーに認証情報を送信して処理し、例外を処理します。
- 認証情報マネージャーをインスタンス化する:
- 復元キーでログインする: 復元キーでログインする手順は次のとおりです。
- アプリサーバーから認証情報取得オプションを取得する: アプリサーバーから復元キーを取得するために必要な詳細情報をクライアント アプリに送信します。
- 復元キーを取得する: ユーザーが新しいデバイスをセットアップするときに、認証情報マネージャーから復元キーをリクエストします。これにより、ユーザーは追加の入力をせずにログインできます。
- 認証情報の取得レスポンスを処理する: クライアント アプリからアプリサーバーに復元キーを送信して、ユーザーをログインさせます。
- 復元キーを削除します。
復元キーを作成する
アプリは、ユーザーがログインするすべてのケースに対応し、アクティブ ユーザーに復元キーが作成されるようにする必要があります。次のシナリオでは、復元キーを作成します。
- ユーザーがログインしていて、復元キーがまだ作成されていない場合(メインの
ActivityのonCreateメソッドなど)。 - ユーザーがログインしているとき、または新しいアカウントの登録フローを完了しているとき。
パフォーマンスを最適化し、ログインのたびに復元認証情報の作成や確認を行うオーバーヘッドを回避するには、boolean フラグまたは認証情報作成タイムスタンプ(has_synced_restore_credential など)をローカル ストレージに設定して、鍵がすでに作成されているかどうかを追跡します。
認証情報マネージャーをインスタンス化する
アプリのアクティビティ コンテキストを使用して CredentialManager オブジェクトをインスタンス化します。
// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)
アプリサーバーから認証情報作成オプションを取得する
アプリサーバーで FIDO 準拠のライブラリを使用して、ユーザー、アプリ、追加の構成プロパティなどの復元認証情報の作成に必要な情報をクライアント アプリに送信します。サーバーサイドの実装について詳しくは、サーバーサイドのガイダンスをご覧ください。
復元キーを作成する
サーバーから送信された公開鍵作成オプションを解析した後、これらのオプションを CreateRestoreCredentialRequest オブジェクトでラップし、CredentialManager オブジェクトで createCredential() メソッドを呼び出して、復元鍵を作成します。
// createRestoreRequest contains the details sent by the server
val response = credentialManager.createCredential(context, createRestoreRequest)
コードに関する主なポイント
CreateRestoreCredentialRequestオブジェクトには次のフィールドがあります。requestJson:PublicKeyCredentialCreationOptionsJSONの Web Authentication API 形式でアプリサーバーから送信される認証情報の作成オプション。isCloudBackupEnabled: 復元キーをクラウドにバックアップするかどうかを決定するBooleanフィールド。デフォルトでは、このフラグはtrueです。このフィールドには次の値があります。true:(推奨)この値を指定すると、ユーザーが Google バックアップとエンドツーエンド暗号化(画面ロックなど)を有効にしている場合、復元キーのクラウドへのバックアップが有効になります。false: この値は、鍵をクラウドではなくローカルに保存します。ユーザーがクラウドから復元することを選択した場合、新しいデバイスでキーを利用することはできません。
認証情報の作成レスポンスを処理する
Credential Manager API は、CreateRestoreCredentialResponse 型のレスポンスを返します。このレスポンスには、公開鍵認証情報の登録レスポンスが JSON 形式で保持されます。
アプリから証明書利用者サーバーに公開鍵を送信します。この公開鍵は、パスキーの作成時に生成される公開鍵と似ています。サーバーでパスキーの作成を処理するのと同じコードで、復元キーの作成も処理できます。サーバーサイドの実装について詳しくは、パスキーのガイダンスをご覧ください。
復元キーの作成プロセス中に、次の例外を処理します。
CreateRestoreCredentialDomException:requestJsonが無効で、PublicKeyCredentialCreationOptionsJSONの WebAuthn 形式に従っていない場合に発生します。E2eeUnavailableException:isCloudBackupEnabledがtrueであるにもかかわらず、ユーザーのデバイスにデータ バックアップやエンドツーエンドの暗号化(画面ロックなど)がない場合、この例外が発生します。
復元用認証情報が常に作成されるようにするには、isCloudBackupEnabledをtrueに設定してcreateCredentialを呼び出すことで、E2eeUnavailableExceptionを明示的に処理する必要があります。E2eeUnavailableExceptionがスローされた場合は、キャッチしてisCloudBackupEnabledをfalseに設定してcreateCredentialを再度呼び出します。IllegalArgumentException:createRestoreRequestが空であるか、有効な JSON ではない場合、または WebAuthn 仕様に準拠した有効なuser.idがない場合に、この例外が発生します。
復元キーを使用してログインする
デバイスのセットアップ プロセス中に、Restore Credentials を使用してユーザーをサイレントでログインさせます。
アプリサーバーから認証情報取得オプションを取得する
サーバーから復元キーを取得するために必要なオプションをクライアント アプリに送信します。この手順に関する同様のパスキーのガイダンスについては、パスキーでログインするをご覧ください。サーバーサイドの実装について詳しくは、サーバーサイド認証ガイドをご覧ください。
復元キーを取得する
新しいデバイスで復元キーを取得するには、CredentialManager オブジェクトで getCredential() メソッドを呼び出します。
次の両方のシナリオで復元キーを取得することをおすすめします。
- デバイスでアプリを初めて起動したとき。このシナリオでの認証情報の復元は、アプリデータの復元とは独立しています。
- アプリデータのバックアップと復元が有効になっている場合は、アプリデータの復元直後に復元キーを取得します。
BackupAgentを使用してアプリのバックアップを設定し、onRestoreFinishedコールバック内でgetCredential機能が完了するようにします。onRestoreメソッドは Key-Value バックアップでのみ呼び出されるため、使用しないでください。onRestoreFinishedはあらゆる種類のバックアップ復元で確実に呼び出されます。これにより、ユーザーが新しいデバイスを初めて開いたときに遅延が発生するのを防ぎ、ユーザーがアプリを開くのを待たずにアプリを操作できるようになります。たとえば、新しいデバイスでアプリを初めて開く前に、アプリからユーザーに通知を送信できます。これは、メッセージ アプリやコミュニケーション アプリで特に重要です。
BackupAgent を新たに作成し、以前に allowBackup="true" でバックアップを有効にしていた場合は、アプリのマニフェストでブール値 android:fullBackupOnly="true" を設定します。これにより、アプリのバックアップと復元の動作が維持されます。
// 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
認証情報マネージャー API は、GetCredentialResponse 型のレスポンスを返します。このレスポンスに含まれる認証情報は、公開鍵を保持する RestoreCredential 型であることが明示的に示されています。
ログイン レスポンスを処理する
アプリから証明書利用者サーバーに公開鍵を送信します。この公開鍵はユーザーのログインに使用できます。サーバー側では、このアクションはパスキーを使用したログインに似ています。サーバーでパスキーによるログインを処理する同じコードで、復元キーによるログインも処理できます。パスキーのサーバーサイド実装について詳しくは、パスキーでログインするをご覧ください。
復元キーを削除する
認証情報マネージャーはステートレスでユーザー アクティビティを認識しないため、使用後に復元キーを自動的に削除することはありません。復元キーを削除するには、clearCredentialState() メソッドを呼び出します。セキュリティのため、ユーザーがログアウトするたびにキーを削除します。これにより、ユーザーが同じデバイスで次回アプリを開いたときに、ユーザーはログアウトされ、再度ログインするよう求められます。
アプリのアンインストールは、ログアウト時のユーザーの意図と同様に、対応する復元キーをデバイスから削除する意図と解釈されます。
復元キーは、次の場合にのみ削除されます。
- システムレベルのアクション: ユーザーがアプリをアンインストールするか、アプリのデータを消去します。
- アプリレベルの呼び出し: アプリのコードでユーザーのログアウトを処理するときに、
clearCredentialState()を呼び出してキーをプログラムで削除します。
ユーザーがアプリからログアウトしたら、CredentialManager オブジェクトの clearCredentialState() メソッドを呼び出します。
// 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)