ホルダーアプリで認証情報の発行を処理する

発行元から認証情報を受け取って保存するには、ホルダーアプリで発行フローを処理する必要があります。認証情報の発行は、次の 2 つの方法でトリガーできます。

  • カード発行会社が開始するフロー: ユーザーがカード発行会社のアプリまたはウェブサイトから VDC の発行リクエストをトリガーします。たとえば、ウェブサイトでユーザーに「パスポートをウォレットに追加する」オプションを提供できます。発行元は、Credential Manager 発行 API を呼び出して、OpenID4VCI 認証情報オファー リクエストを送信します。このようなリクエストを処理するには、ホルダーはまず認証情報マネージャーと統合してメタデータを登録する必要があります。認証情報マネージャーには、ユーザーが選択できる関連オプションが表示されます。ユーザーがホルダー オプションを選択すると、ホルダー アプリケーションが呼び出され、発行を完了するために必要な手順に進むことができます。
  • ホルダー主導のフロー: ユーザーがホルダー アプリケーションから VDC の追加をリクエストします。たとえば、ホルダーは「パスポートを追加」ボタンを提供できます。この場合、ホルダーはサポートされている発行元のリストとメタデータを保持します。この機能を完了するために、Android 認証情報マネージャーと統合する必要はありません。

Holder API での認証情報の仕組みについては、デジタル認証情報の保存についてをご覧ください。

Android バージョンの互換性

Holder API は、Android 6(API レベル 23)以降でサポートされています。

実装

Credential Manager Holder API を使用するには、アプリ モジュールのビルド スクリプトに次の依存関係を追加します。

Groovy

dependencies {
    // Use to implement credentials registrys

    implementation "androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-digitalcredentials-openid:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-digitalcredentials-sdjwtvc:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-provider:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04"

}

Kotlin

dependencies {
    // Use to implement credentials registrys

    implementation("androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-digitalcredentials-openid:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-digitalcredentials-sdjwtvc:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-provider:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04")

}

RegistryManager を作成する

RegistryManager インスタンスを作成し、RegisterCreationOptionsRequest リクエストを登録します。

val registryManager = RegistryManager.create(context)

try {
    registryManager.registerCreationOptions(object :
        RegisterCreationOptionsRequest(
            creationOptions = buildIssuanceData(),
            matcher = loadIssuanceMatcher(),
            type = DigitalCredential.TYPE_DIGITAL_CREDENTIAL,
            id = "openid4vci",
        ) {}
    )
} catch (e: Exception) {
    Log.e(TAG, "Issuance registration failed.", e)
}

マッチャーは、登録時に設定された creationOptions と、発行元から送信された認証情報のオファーを受け取り、認証情報マネージャーの UI に表示されるエントリを決定する WebAssembly(Wasm)バイナリ ファイルです。マッチャーの例については、オープンソースのサンプル ウォレット アプリをご覧ください。

発行リクエストを処理する

次に、ウォレットは、ユーザーが認証情報の作成オプションを選択したときに処理する必要があります。サンプル ウォレットに示すように、androidx.credentials.registry.provider.action.CREATE_CREDENTIAL インテント フィルタをリッスンするアクティビティを定義します。

アクティビティを起動するインテントには、作成リクエストと呼び出し元が含まれています。これらは PendingIntentHandler.retrieveProviderCreateCredentialRequest 関数で抽出できます。API は、作成リクエストに関連するすべての情報を含む ProviderCreateCredentialRequest を返します。主なコンポーネントは次の 2 つです。

  • リクエストを行ったアプリ。これは getCallingAppInfo で取得できます。
  • 呼び出し元アプリからのリクエスト。これは getCallingRequest で取得できます。CreateCredentialRequest が返されます。リクエストがデジタル認証情報に関するものである場合、これは CreateDigitalCredentialRequest のインスタンスであり、requestJson プロパティに発行リクエストの JSON が含まれています。これは、次のサンプルコードで処理できます。
val pendingIntentRequest =
    PendingIntentHandler.retrieveProviderCreateCredentialRequest(intent)
val request = pendingIntentRequest!!.callingRequest
if (request is CreateDigitalCredentialRequest) {
    Log.i(TAG, "Got DC creation request: ${request.requestJson}")
    processCreationRequest(request.requestJson)
}

鍵構成証明

キー構成証明については、次の点に注意してください。

  • キー構成証明を生成するときに、BigInteger.toByteArray を使用して鍵マテリアルを JSON ウェブキーなどに変換することがあります。このメソッドでは、符号バイトが追加され、検証エラーが発生することがあります。この場合は、キー構成証明をカード発行会社に送信する前に、これらのバイトを削除します。
  • 鍵証明タイプとして android_key_attestation を使用することをおすすめします。

作成レスポンスを返す

ウォレットが認証情報の保存に必要な手順を完了したら、認証情報のレスポンスでアクティビティを終了します。

val resultData = Intent()
PendingIntentHandler.setCreateCredentialResponse(
    resultData,
    CreateDigitalCredentialResponse(response.responseJson)
)
setResult(RESULT_OK, resultData)
finish()

例外がある場合は、同様に認証情報の例外を送信できます。

val resultData = Intent()
PendingIntentHandler.setCreateCredentialException(
    resultData,
    CreateCredentialUnknownException() // Configure the proper exception
)
setResult(RESULT_OK, resultData)
finish()

コンテキストで認証情報レスポンスを返す完全な例については、サンプルアプリをご覧ください。