Credential Verifier API

Android アプリ内のデジタル認証情報の検証は、ユーザーの身元(政府発行の身分証明書など)、そのユーザーに関するプロパティ(運転免許証、学位、年齢や住所などの属性など)、またはエンティティの真正性を確認するために認証情報の発行と検証が必要なその他のシナリオの認証と承認に使用できます。

デジタル認証情報は、デジタル ウォレットからユーザーの検証可能なデジタル認証情報にアクセスする方法を指定した公開 W3C 標準です。ウェブのユースケース向けに、W3C 認証情報管理 API を使用して実装されています。Android では、デジタル認証情報の検証に Credential Manager の DigitalCredential API が使用されます。

実装

Android プロジェクトでデジタル認証情報を確認する手順は次のとおりです。

  1. アプリのビルド スクリプトに依存関係を追加し、CredentialManager クラスを初期化します。
  2. デジタル認証情報リクエストを作成し、それを使用して DigitalCredentialOption を初期化してから、GetCredentialRequest をビルドします。
  3. 作成したリクエストを使用して getCredential フローを起動し、成功した GetCredentialResponse を受信するか、発生する可能性のある例外を処理します。取得に成功したら、レスポンスを検証します。

依存関係を追加して初期化する

Gradle ビルド スクリプトに次の依存関係を追加します。

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

次に、CredentialManager クラスのインスタンスを初期化します。

val credentialManager = CredentialManager.create(context)

デジタル認証情報リクエストを作成する

デジタル認証情報リクエストを作成し、DigitalCredentialOption の初期化に使用します。

// The request in the JSON format to conform with
// the JSON-ified Digital Credentials API request definition.
val requestJson = generateRequestFromServer()
val digitalCredentialOption =
    GetDigitalCredentialOption(requestJson = requestJson)

// Use the option from the previous step to build the `GetCredentialRequest`.
val getCredRequest = GetCredentialRequest(
    listOf(digitalCredentialOption)
)

OpenId4Vp リクエストの例を次に示します。詳細なリファレンスは、こちらのウェブサイトでご覧いただけます。

{
  "digital": {
    "requests": [
      {
        "protocol": "openid4vp-v1-unsigned",
        "data": {
          "response_type": "vp_token",
          "response_mode": "dc_api",
          "nonce": "OD8eP8BYfr0zyhgq4QCVEGN3m7C1Ht_No9H5fG5KJFk",
          "dcql_query": {
            "credentials": [
              {
                "id": "cred1",
                "format": "mso_mdoc",
                "meta": {
                  "doctype_value": "org.iso.18013.5.1.mDL"
                },
                "claims": [
                  {
                    "path": [
                      "org.iso.18013.5.1",
                      "family_name"
                    ]
                  },
                  {
                    "path": [
                      "org.iso.18013.5.1",
                      "given_name"
                    ]
                  },
                  {
                    "path": [
                      "org.iso.18013.5.1",
                      "age_over_21"
                    ]
                  }
                ]
              }
            ]
          }
        }
      }
    ]
  }
}

認証情報を取得する

作成したリクエストを使用して getCredential フローを開始します。成功した場合は GetCredentialResponse が返され、リクエストが失敗した場合は GetCredentialException が返されます。

getCredential フローでは、Android システム ダイアログがトリガーされ、ユーザーが使用できる認証情報のオプションが表示され、ユーザーの選択が収集されます。次に、選択した認証情報オプションを含むウォレット アプリに UI が表示され、同意を収集し、デジタル認証情報レスポンスを生成するために必要なアクションを実行します。

coroutineScope.launch {
    try {
        val result = credentialManager.getCredential(
            context = activityContext,
            request = getCredRequest
        )
        verifyResult(result)
    } catch (e : GetCredentialException) {
        handleFailure(e)
    }
}

// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
    val credential = result.credential
    when (credential) {
        is DigitalCredential -> {
            val responseJson = credential.credentialJson
            validateResponseOnServer(responseJson)
        }
        else -> {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential ${credential.type}")
        }
    }
}

// Handle failure.
fun handleFailure(e: GetCredentialException) {
  when (e) {
        is GetCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to share the credential.
        }
        is GetCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is NoCredentialException -> {
            // No credential was available.
        }
        is CreateCredentialUnknownException -> {
            // An unknown, usually unexpected, error has occurred. Check the
            // message error for any additional debugging information.
        }
        is CreateCredentialCustomException -> {
            // You have encountered a custom error thrown by the wallet.
            // If you made 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}")
    }
}