認証情報マネージャー - Verifier API

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

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

Android バージョンの互換性

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

実装

Android プロジェクトでデジタル認証情報を検証するには、次の操作を行います。

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

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

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

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

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

val credentialManager = CredentialManager.create(context)

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

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

// The request in the JSON format to conform with
// the JSON-ified Credential Manager - Verifier 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 リクエストの例を次に示します。完全なリファレンスについては、 こちらのウェブサイトをご覧ください。

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