デジタル ID は、アプリ内フローとウェブフローの両方で受け付けられます。Google ウォレットの認証情報を受け入れるには、次の操作を行う必要があります。
- 提供された手順に沿って、アプリまたはウェブを使用して統合します。
- テスト ID を使用して、Google ウォレットのサンドボックスでフローをテストします。
- リリースするには、こちらのフォームに記入してアクセスをリクエストし、Google ウォレットの認証情報の利用規約に同意してください。このフォームは、各事業体について記入する必要があります。フォームにご記入いただいた後、担当チームよりご連絡いたします。
- ご不明な点がございましたら、
wallet-identity-rp-support@google.comまでお問い合わせください。
サポートされている認証情報の形式
デジタル ID ドキュメントのデータ形式を定義する標準案がいくつか存在し、そのうち 2 つが業界で大きな支持を得ています。
- mdocs - ISO によって定義されます。
- w3c 検証可能な認証情報 - w3c によって定義されます。
Android 認証情報マネージャーは両方の形式をサポートしていますが、現時点では Google ウォレットは mdoc ベースのデジタル ID のみをサポートしています。
サポートされている認証情報
Google ウォレットは 2 種類の認証情報に対応しています。
- モバイル運転免許証(mDL)
- ID パス
フローで 1 つのパラメータを変更するだけで、どちらの認証情報もリクエストできます。
ユーザー エクスペリエンス
このセクションでは、推奨されるオンライン プレゼンテーションのフローについて説明します。このフローは、アルコール飲料の配達アプリに年齢を提示する流れを示していますが、ウェブや他の種類の提示でも UX は同様です。
![]() |
![]() |
![]() |
![]() |
![]() |
| アプリまたはウェブサイトで年齢確認を求められる | ユーザーに利用可能な資格情報が表示される | Google ウォレットに確認ページが表示される | ユーザーが認証して共有を確認する | アプリまたはウェブサイトに送信されるデータ |
重要な注意事項
- アプリやウェブサイトは、API へのエントリ ポイントの作成方法を柔軟に選択できます。ステップ 1 で示したように、API を通じて Google ウォレット以外のオプションも利用できるようになることが予想されるため、[デジタル ID で確認] などの汎用的なボタンを表示することをおすすめします。
- ステップ 2 の選択画面は Android によってレンダリングされます。有効な認証情報は、各ウォレットが提供する登録ロジックと、証明書利用者から送信されたリクエストとの照合によって決定されます。
- ステップ 3 は Google ウォレットによってレンダリングされます。この画面には、デベロッパーが提供した名前、ロゴ、プライバシー ポリシーが表示されます。
デジタル ID フローを追加する
ユーザーが認証情報を持っていない場合は、[デジタル ID で確認] ボタンの横に、Google ウォレットへのディープリンクを介してユーザーがデジタル ID を追加できるようにするリンクを提供することをおすすめします。
![]() |
![]() |
| アプリまたはウェブサイトで年齢確認を求められる | デジタル ID を取得するために Google ウォレットに移動するユーザー |
利用可能なデジタル ID がありません
ユーザーがデジタル ID を持っていない状態で [デジタル ID で確認] オプションを選択すると、このエラー メッセージが表示されます。
![]() |
![]() |
| アプリまたはウェブサイトで年齢確認を求められる | デジタル ID をお持ちでないお客様にエラーが表示される |
ユーザーのプライバシーを保護するため、ユーザーが利用可能なデジタル ID を持っているかどうかをサイレントに学習する機能は API でサポートされていません。そのため、図のようにオンボーディング リンク オプションを含めることをおすすめします。
ウォレットから ID 認証情報をリクエストするためのリクエスト フォーマット
Android デバイスまたはウェブ上の任意のウォレットから ID 認証情報を取得するための mdoc requestJson リクエストの例を次に示します。
{
"requests" : [
{
"protocol": "openid4vp-v1-unsigned",
"data": {<credential_request>} // This is an object, shouldn't be a string.
}
]
}
リクエストの暗号化
client_metadata には、リクエストごとの暗号化公開鍵が含まれています。リクエストごとの秘密鍵を保存し、それを使用してウォレット アプリから受け取ったトークンを認証して承認する必要があります。
requestJson の credential_request パラメータは、次のフィールドで構成されます。
特定の認証情報
{
"response_type": "vp_token",
"response_mode": "dc_api.jwt", // change this to dc_api if you want to demo with a non encrypted response.
"nonce": "1234",
"dcql_query": {
"credentials": [
{
"id": "cred1",
"format": "mso_mdoc",
"meta": {
"doctype_value": "org.iso.18013.5.1.mDL" // this is for mDL. Use com.google.wallet.idcard.1 for ID pass
},
"claims": [
{
"path": [
"org.iso.18013.5.1",
"family_name"
],
"intent_to_retain": false // set this to true if you are saving the value of the field
},
{
"path": [
"org.iso.18013.5.1",
"given_name"
],
"intent_to_retain": false
},
{
"path": [
"org.iso.18013.5.1",
"age_over_18"
],
"intent_to_retain": false
}
]
}
]
},
"client_metadata": {
"jwks": {
"keys": [ // sample request encryption key
{
"kty": "EC",
"crv": "P-256",
"x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
"y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
"use": "enc",
"kid" : "1", // This is required
"alg" : "ECDH-ES", // This is required
}
]
},
"vp_formats_supported": {
"mso_mdoc": {
"deviceauth_alg_values": [
-7
],
"isserauth_alg_values": [
-7
]
}
}
}
}
対象となる認証情報
ここでは、mDL と idpass の両方のリクエストの例を示します。ユーザーはどちらか一方の手続きを進めることができます。
{
"response_type": "vp_token",
"response_mode": "dc_api.jwt", // change this to dc_api if you want to demo with a non encrypted response.
"nonce": "1234",
"dcql_query": {
"credentials": [
{
"id": "mdl-request",
"format": "mso_mdoc",
"meta": {
"doctype_value": "org.iso.18013.5.1.mDL"
},
"claims": [
{
"path": [
"org.iso.18013.5.1",
"family_name"
],
"intent_to_retain": false // set this to true if you are saving the value of the field
},
{
"path": [
"org.iso.18013.5.1",
"given_name"
],
"intent_to_retain": false
},
{
"path": [
"org.iso.18013.5.1",
"age_over_18"
],
"intent_to_retain": false
}
]
},
{ // Credential type 2
"id": "id_pass-request",
"format": "mso_mdoc",
"meta": {
"doctype_value": "com.google.wallet.idcard.1"
},
"claims": [
{
"path": [
"org.iso.18013.5.1",
"family_name"
],
"intent_to_retain": false // set this to true if you are saving the value of the field
},
{
"path": [
"org.iso.18013.5.1",
"given_name"
],
"intent_to_retain": false
},
{
"path": [
"org.iso.18013.5.1",
"age_over_18"
],
"intent_to_retain": false
}
]
}
]
credential_sets : [
{
"options": [
[ "mdl-request" ],
[ "id_pass-request" ]
]
}
]
},
"client_metadata": {
"jwks": {
"keys": [ // sample request encryption key
{
"kty": "EC",
"crv": "P-256",
"x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
"y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
"use": "enc",
"kid" : "1", // This is required
"alg" : "ECDH-ES", // This is required
}
]
},
"vp_formats_supported": {
"mso_mdoc": {
"deviceauth_alg_values": [
-7
],
"isserauth_alg_values": [
-7
]
}
}
}
}
Google ウォレットに保存されている ID 認証情報から、任意の数のサポートされている属性をリクエストできます。
アプリ内
Android アプリから ID 認証情報をリクエストする手順は次のとおりです。
依存関係を更新する
プロジェクトの build.gradle で、認証情報マネージャー(ベータ版)を使用するように依存関係を更新します。
dependencies {
implementation("androidx.credentials:credentials:1.5.0-beta01")
// optional - needed for credentials support from play services, for devices running Android 13 and below.
implementation("androidx.credentials:credentials-play-services-auth:1.5.0-beta01")
}
Credential Manager を構成する
CredentialManager オブジェクトを構成して初期化するには、次のようなロジックを追加します。
// Use your app or activity context to instantiate a client instance of CredentialManager.
val credentialManager = CredentialManager.create(context)
ID 属性をリクエストする
ID リクエストに個々のパラメータを指定する代わりに、アプリは CredentialOption 内の JSON 文字列としてすべてのパラメータをまとめて提供します。Credential Manager は、この JSON 文字列の内容を調べずに、利用可能なデジタル ウォレットに渡します。各ウォレットは、JSON 文字列を解析して ID リクエストを理解する役割を担います。- 保存されている認証情報のうち、リクエストを満たすものを判断する。
Android アプリの統合の場合でも、サーバーでリクエストを作成することをおすすめします。
GetDigitalCredentialOption() 関数呼び出しで request を構成する リクエスト形式の requestJson を使用します。
// 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)
)
coroutineScope.launch {
try {
val result = credentialManager.getCredential(
context = activityContext,
request = getCredRequest
)
verifyResult(result)
} catch (e : GetCredentialException) {
handleFailure(e)
}
}
レスポンスを確認して検証する
ウォレットからレスポンスが返ってきたら、レスポンスが成功し、credentialJson レスポンスが含まれているかどうかを確認します。
// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
val credential = result.credential
when (credential) {
is DigitalCredential -> {
val responseJson = credential.credentialJson
validateResponseOnServer(responseJson) // make a server call to validate the response
}
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.
}
else -> Log.w(TAG, "Unexpected exception type ${e::class.java}")
}
}
credentialJson レスポンスには、W3C で定義された暗号化された identityToken(JWT)が含まれます。このレスポンスの作成はウォレット アプリが行います。
例:
{
"protocol" : "openid4vp-v1-unsigned",
"data" : {
<encrpted_response>
}
}
このレスポンスをサーバーに渡して、信頼性を検証します。認証情報のレスポンスを検証する手順をご覧ください。
ウェブ
Chrome またはその他のサポートされているブラウザで Digital Credentials API を使用して Identity Credentials をリクエストするには、次のリクエストをトリガーします。
const credentialResponse = await navigator.credentials.get({
digital : {
requests : [
{
protocol: "openid4vp-v1-unsigned",
data: {<credential_request>} // This is an object, shouldn't be a string.
}
]
}
})
この API からのレスポンスをサーバーに送り返して、認証情報のレスポンスを検証します。
認証情報のレスポンスを検証する手順
アプリまたはウェブサイトから暗号化された identityToken を受け取ったら、レスポンスを信頼する前に複数の検証を行う必要があります。
秘密鍵を使用してレスポンスを復号する
まず、保存した秘密鍵を使用してトークンを復号し、レスポンス JSON を取得します。
Python の例:
from jwcrypto import jwe, jwk # Retrieve the Private Key from Datastore reader_private_jwk = jwk.JWK.from_json(jwe_private_key_json_str) # Save public key thumbprint for session transcript encryption_public_jwk_thumbprint = reader_private_jwk.thumbprint() # Decrypt the JWE encrypted response from Google Wallet jwe_object = jwe.JWE() jwe_object.deserialize(encrypted_jwe_response_from_wallet) jwe_object.decrypt(reader_private_jwk) decrypted_payload_bytes = jwe_object.payload decrypted_data = json.loads(decrypted_payload_bytes)decrypted_dataは、認証情報を含むvp_tokenJSON を返します。{ "vp_token": { "cred1": "<credential_token>" } }セッションの文字起こしを作成する
次のステップでは、Android またはウェブ固有のハンドオーバー構造を使用して、ISO/IEC 18013-5:2021 から SessionTranscript を作成します。
SessionTranscript = [ null, // DeviceEngagementBytes not available null, // EReaderKeyBytes not available [ "OpenID4VPDCAPIHandover", AndroidHandoverDataBytes // BrowserHandoverDataBytes for Web ] ]Android とウェブの両方のハンドオーバーで、
credential_requestの生成に使用したのと同じ nonce を使用する必要があります。Android ハンドオーバー
AndroidHandoverData = [ origin, // "android:apk-key-hash:<base64SHA256_ofAppSigningCert>", nonce, // nonce that was used to generate credential request, encryption_public_jwk_thumbprint, // Encryption public key (JWK) Thumbprint ] AndroidHandoverDataBytes = hashlib.sha256(cbor2.dumps(AndroidHandoverData)).digest()
ブラウザ ハンドオーバー
BrowserHandoverData =[ origin, // Origin URL nonce, // nonce that was used to generate credential request encryption_public_jwk_thumbprint, // Encryption public key (JWK) Thumbprint ] BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
SessionTranscriptを使用して、ISO/IEC 18013-5:2021 の条項 9 に従って DeviceResponse を検証する必要があります。これには、次のような複数のステップが含まれます。State Issuer Cert を確認します。サポートされている発行者の IACA 証明書を確認する
MSO 署名を検証する(18013-5 セクション 9.1.2)
データ要素の ValueDigest を計算して確認する(18013-5 セクション 9.1.2)
deviceSignature署名を検証する(18013-5 セクション 9.1.3)
{
"version": "1.0",
"documents": [
{
"docType": "org.iso.18013.5.1.mDL",
"issuerSigned": {
"nameSpaces": {...}, // contains data elements
"issuerAuth": [...] // COSE_Sign1 w/ issuer PK, mso + sig
},
"deviceSigned": {
"nameSpaces": 24(<< {} >>), // empty
"deviceAuth": {
"deviceSignature": [...] // COSE_Sign1 w/ device signature
}
}
}
],
"status": 0
}
ソリューションをテストする
ソリューションをテストするには、Google のオープンソース リファレンス ホルダーである Android アプリをビルドして実行します。このリファレンス ホルダー アプリをビルドして実行する手順は次のとおりです。
- リファレンス アプリのリポジトリのクローンを作成します。
- Android Studio でプロジェクトを開きます。
appholderターゲットをビルドし、Android デバイスまたはエミュレータで実行します。
ゼロ知識証明(ZKP)に基づく確認
ゼロ知識証明(ZKP)は、個人(証明者)が、実際の基盤となるデータ自体を開示することなく、特定の身元情報を持っていることや特定の基準を満たしていること(18 歳以上である、有効な資格情報を保持しているなど)を検証者に証明できる暗号手法です。つまり、機密情報を非公開のまま、自分の身元に関するステートメントの真実性を確認する方法です。
ID データの直接共有に依存するデジタル ID システムでは、ユーザーが過剰な個人情報を共有する必要があることが多く、データ侵害や ID 盗用のリスクが高まります。ZKP はパラダイム シフトをもたらし、最小限の開示で検証を可能にします。
デジタル ID における ZKP の主なコンセプト:
- 証明者: 自分の身元の一面を証明しようとしている個人。
- 検証ツール: ID 属性の証明をリクエストするエンティティ。
- 証明: 秘密情報を開示することなく、証明者が検証者に主張の真実性を納得させることを可能にする暗号化プロトコル。
ゼロ知識証明の主な特性:
- 完全性: ステートメントが true で、証明者と検証者の両方が正直であれば、検証者は納得します。
- 健全性: ステートメントが false の場合、不正な証明者は(非常に高い確率で)正直な検証者にステートメントが true であると納得させることができません。
- ゼロ知識: 検証者は、ステートメントが真実であるという事実以外は何も学習しません。証明者の身元に関する実際のデータは公開されません。
Google ウォレットからゼロ知識証明を取得するには、リクエスト形式を mso_mdoc_zk に変更し、リクエストに zk_system_type を追加する必要があります。
...
"dcql_query": {
"credentials": [{
"id": "cred1",
"format": "mso_mdoc_zk",
"meta": {
"doctype_value": "org.iso.18013.5.1.mDL"
"zk_system_type": [
{
"system": "longfellow-libzk-v1",
"circuit_hash": "bd3168ea0a9096b4f7b9b61d1c210dac1b7126a9ec40b8bc770d4d485efce4e9", // This will differ if you need more than 1 attribute.
"num_attributes": 1, // number of attributes (in claims) this has can support
"version": 3
},
{
"system": "longfellow-libzk-v1",
"circuit_hash": "89288b9aa69d2120d211618fcca8345deb4f85d2e710c220cc9c059bbee4c91f", // This will differ if you need more than 1 attribute.
"num_attributes": 1, // number of attributes (in claims) this has can support
"version": 4
}
{
"system": "longfellow-libzk-v1",
"circuit_hash": "f88a39e561ec0be02bb3dfe38fb609ad154e98decbbe632887d850fc612fea6f", // This will differ if you need more than 1 attribute.
"num_attributes": 1, // number of attributes (in claims) this has can support
"version": 5
}
{
"system": "longfellow-libzk-v1",
"circuit_hash": "137e5a75ce72735a37c8a72da1a8a0a5df8d13365c2ae3d2c2bd6a0e7197c7c6", // This will differ if you need more than 1 attribute.
"num_attributes": 1, // number of attributes (in claims) this has can support
"version": 6
}
],
"verifier_message": "challenge"
},
"claims": [{
...
"client_metadata": {
"jwks": {
"keys": [ // sample request encryption key
{
...
ウォレットから暗号化されたゼロ知識証明が返されます。この証明書は、Google の longfellow-zk ライブラリを使用して、発行者の IACA 証明書に対して検証できます。
verifier-service には、特定の発行者 IACA 証明書に対してレスポンスを検証できる、デプロイ準備完了の Docker ベースのサーバーが含まれています。
certs.pem を変更して、信頼する IACA 発行者の証明書を管理できます。
詳細については、サポート メールにお問い合わせください。
wallet-identity-rp-support@google.com







