パスキーを作成する

ユーザーがパスキーで認証を行うには、まずアプリでユーザーのアカウントのパスキーを登録または作成する必要があります。

パスキーを作成するには、パスキーの作成に必要な詳細情報をアプリサーバーから取得し、Credential Manager API を呼び出します。この API は、公開鍵と秘密鍵のペアを返します。返された秘密鍵は、Google パスワード マネージャーなどの認証情報プロバイダにパスキーとして保存されます。公開鍵はアプリサーバーに保存されます。

パスキーは認証情報プロバイダに保存され、公開鍵はアプリサーバーに保存されます
図 1: パスキーの作成

前提条件

Digital Asset Links を設定し、Android 9(API レベル 28)以降を搭載している デバイスをターゲットにしていることを確認します。

概要

このガイドでは、パスキーを作成するために証明書利用者クライアント アプリに必要な変更について説明し、証明書利用者アプリサーバーの実装の概要を示します。サーバーサイドの実装について詳しくは、 サーバーサイドでのパスキー登録をご覧ください。

  1. アプリに依存関係を追加する: 必要な認証情報マネージャー ライブラリを追加します。
  2. 認証情報マネージャーをインスタンス化する: 認証情報マネージャーインスタンスを作成します。
  3. アプリサーバーから認証情報作成オプションを取得する: アプリ サーバーから、アプリ、ユーザー、challenge、その他の フィールドに関する情報など、パスキーの作成に必要な詳細情報をクライアント アプリに送信します。
  4. パスキーをリクエストする: アプリで、 アプリサーバーから受信した詳細情報を使用して GetPublicKeyCredentialOption オブジェクトを作成し、 このオブジェクトを使用して credentialManager.getCredential() メソッドを 呼び出してパスキーを作成します。
  5. パスキー作成レスポンスを処理する: クライアント アプリで 認証情報を受信したら、公開鍵をエンコードしてシリアル化し、アプリサーバーに送信する必要があります。また、パスキーの作成時に発生する可能性のある例外をそれぞれ処理する必要があります。
  6. サーバーで公開鍵を検証して保存する: サーバーサイドの手順を完了して認証情報の送信元を検証し、 公開鍵を保存します。
  7. ユーザーに通知する: パスキーが 作成されたことをユーザーに通知します。

アプリに依存関係を追加する

アプリ モジュールの 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"
}

認証情報マネージャーをインスタンス化する

アプリまたはアクティビティのコンテキストを使用して CredentialManager オブジェクトを作成します。

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

アプリサーバーから認証情報作成オプションを取得する

ユーザーが [パスキーを作成] ボタンをクリックしたとき、または新規ユーザーが登録したときに、アプリからアプリサーバーにリクエストを送信して、パスキー登録プロセスを開始するために必要な情報を取得します。

アプリサーバーで FIDO 準拠のライブラリを使用して、ユーザー、アプリ、追加の構成プロパティに関する情報など、パスキーの作成に必要な情報をクライアント アプリに送信します。詳しくは、サーバー サイドでのパスキー登録をご覧ください

クライアント アプリで、アプリサーバーから送信された公開鍵作成オプションをデコードします。通常、これらは JSON 形式で表されます。ウェブ クライアントでこのデコードを行う方法について詳しくは、エンコードと デコードをご覧ください。Android クライアント アプリの場合は、デコードを個別に処理する必要があります。

次のスニペットは、アプリサーバーから送信された公開鍵作成オプションの構造を示しています。

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

公開鍵作成オプションのキーフィールドは次のとおりです。

  • challenge: リプレイ攻撃を防ぐために使用される、サーバーで生成されたランダムな文字列。
  • rp: アプリに関する詳細情報。
    • rp.name: アプリの名前。
    • rp.id: アプリのドメインまたはサブドメイン。
  • user: ユーザーに関する詳細情報。
    • id: ユーザーの一意の ID。メールアドレスやユーザー名などの個人情報はこの値に含まれません。ランダムな 16 バイトの値を使用できます。
    • name: ユーザーが認識できるアカウントの一意の識別子(メールアドレスやユーザー名など)。この識別子はアカウント選択画面に表示されます (ユーザー名を使用する場合はパスワード認証の値と同じ値を使用します)。
    • displayName: アカウント選択画面に表示するアカウントのわかりやすい名前(省略可)。
  • authenticatorSelection: 認証に使用されるデバイスに関する詳細情報。
    • authenticatorAttachment: 優先する 認証者を示します。使用できる値は次のとおりです。
      • platform: この値は、指紋認証センサーなど、ユーザーのデバイスに組み込まれた認証者で使用されます。
      • cross-platform: この値は、セキュリティ キーなどのローミング デバイスで使用されます。通常、パスキーのコンテキストでは使用されません。
      • 未指定(推奨): この値を指定しないと、ユーザーは任意のデバイスでパスキーを作成できます。ほとんどの場合、このパラメータを指定しないことが最適な方法です。
    • requireResidentKey: パスキーを作成するには、この Boolean フィールドの値を true に設定します。
    • residentKey: パスキーを作成するには、値を required に設定します。
    • userVerification: パスキー登録時のユーザー確認の要件を指定するために使用します。使用できる値は次のとおりです。
      • preferred: ユーザー確認によって保護よりも摩擦が生じる環境など、保護よりもユーザー エクスペリエンスを優先する場合は、この値を使用します。
      • required: デバイスで使用可能なユーザー確認方法の呼び出しが必要な場合は、この値を使用します。
      • discouraged: ユーザー確認方法の使用が推奨されない場合は、この値を使用します。
        について詳しくは、userVerification の詳細をご覧ください
  • excludeCredentials: 同じ認証情報プロバイダのパスキーがすでに存在する場合に重複するパスキーが作成されないように、配列に認証情報 ID をリストします。

パスキーを作成

サーバーサイドの公開鍵作成オプションを解析したら、これらのオプションを CreatePublicKeyCredentialRequest オブジェクトにラップして createCredential() を呼び出し、パスキーを作成します。

createPublicKeyCredentialRequest には次のものが含まれます。

  • requestJson: アプリサーバーから送信された認証情報作成オプション。
  • preferImmediatelyAvailableCredentials:これは省略可能なブール値フィールドで、セキュリティ キーやハイブリッド キーフローの認証情報ではなく、ローカルで利用可能な認証情報または認証情報プロバイダと同期された認証情報のみを使用してリクエストを実行するかどうかを定義します。使用できる値は次のとおりです。
    • false (デフォルト): 認証情報マネージャーの呼び出しがユーザーによる明示的な操作によってトリガーされた場合は、この値を使用します。
    • true: アプリを初めて開くときなど、Credential Manager が機会的に 呼び出される場合は、この値を使用します。
      値を trueに設定した場合に、すぐに利用可能な認証情報がないと、認証情報マネージャーは UI を表示せず、リクエストはすぐに失敗し、get リクエストでは NoCredentialException、create リクエストでは CreateCredentialNoCreateOptionExceptionが返されます。
  • origin: このフィールドは Android アプリで自動的に設定されます。ブラウザや 同様の権限を持つアプリでoriginを設定する必要がある場合は、特権アプリで代理で認証情報 マネージャーの呼び出しを行うをご覧ください。
  • isConditional: これは省略可能なフィールドで、デフォルト値は false です。詳しくは、パスキーを自動的に作成するをご覧ください。

createCredential() 関数を呼び出すと、Credential Manager の組み込みボトムシート UI が起動し、パスキーの使用、保存する認証情報プロバイダとアカウントの選択をユーザーに求めます。ただし、isConditionaltrue に設定されている場合、ボトムシート UI は表示されず、パスキーが自動的に作成されます。

パスキーを自動的に作成する

パスキーの作成時に CreatePublicKeyCredentialRequestisConditional パラメータを true に設定すると、パスワードでのログインが成功した後にユーザーのパスキーを自動的に作成できます。ユーザーがまだパスキーを持っていない場合、アプリはバックグラウンドで自動的にパスキーを作成し、Google パスワード マネージャーなどのユーザーの認証情報プロバイダに保存しようとします。実装例については、公開 サンプルをご覧ください。

パスキーの作成後に Google パスワード マネージャーに表示される通知の例
図 2: Google パスワード マネージャーの通知

レスポンスを処理する

デバイスの画面ロックを使用してユーザーが確認されると、パスキーが作成され、ユーザーが選択した認証情報プロバイダに保存されます。

createCredential() を正常に呼び出した後のレスポンスは、 PublicKeyCredential オブジェクトです。

PublicKeyCredential は次のようになります。

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

クライアント アプリで、オブジェクトをシリアル化してアプリサーバーに送信します。

次のスニペットに示すように、失敗を処理するコードを追加します。

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

アプリサーバーで公開鍵を検証して保存する

アプリサーバーで、公開鍵認証情報を検証してから公開鍵を 保存する必要があります。

公開鍵認証情報の送信元を検証するには、承認済みアプリの許可リストと比較します。キーの送信元が認識されない場合は、拒否します。

アプリの SHA 256 フィンガープリントを取得するには:

  1. ターミナルで次のコマンドを実行して、リリース アプリの署名証明書を出力します。

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

    レスポンスで、署名証明書の SHA 256 フィンガープリント(Certificate fingerprints block : SHA256)を確認します。

  2. SHA256 フィンガープリントを base64url エンコードでエンコードします。次の Python の例は、フィンガープリントを適切にエンコードする方法を示しています。

    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. 前の手順の出力の先頭に android:apk-key-hash: を追加して、次のような結果にします。

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

    結果は、アプリサーバーで許可されている送信元と一致する必要があります。複数の署名証明書(デバッグとリリース用の証明書や複数のアプリなど)がある場合は、このプロセスを繰り返して、すべての送信元をアプリサーバーで有効として受け入れます。

ユーザーに通知する

パスキーが正常に作成されたら、パスキーについてユーザーに通知し、認証情報 プロバイダ アプリまたはアプリの設定からパスキーを管理できることを伝えます。カスタム ダイアログ、通知、スナックバーを使用してユーザーに通知します。悪意のあるエンティティによって予期しないパスキーが作成された場合は、すぐにセキュリティ通知を送信する必要があるため、アプリ内での通知に加えて、メールなどの外部通信も検討してください。

ユーザー エクスペリエンスの向上

Credential Manager を使用して登録を実装する際のユーザー エクスペリエンスを向上させるには、認証情報を復元して自動入力ダイアログを表示しないようにする機能を追加することを検討してください。

新しいデバイスで認証情報を復元する機能を追加する

ユーザーが新しいデバイスでアカウントにシームレスにログインできるようにするには、 認証情報を復元する機能を実装します。BackupAgent を使用して認証情報を復元する機能を追加すると、ユーザーが新しいデバイスで復元したアプリを開いたときにログインし、すぐにアプリを使用できるようになります。

認証情報フィールドの自動入力を抑制する(省略可)

ユーザーが認証に Credential Manager のボトムシート UI を使用することが想定されるアプリ画面の場合は、ユーザー名フィールドとパスワード フィールドに isCredential 属性を追加します。これにより、自動入力ダイアログ(FillDialogSaveDialog)が Credential Manager のボトムシート UI と重複しないようにします。

isCredential 属性は Android 14 以降でサポートされています。

次の例は、アプリの関連するビューの関連するユーザー名フィールドとパスワード フィールドに isCredential 属性を追加する方法を示しています。

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

次のステップ