Langkah 3: Integrasikan sebagai Relying Party

Panduan ini menjelaskan cara Pihak Pengandalkan (RP) Langsung—penjual, bisnis, dan developer aplikasi perorangan—mengintegrasikan Digital Credentials API untuk meminta dan memvalidasi kredensial identitas digital di seluruh aplikasi Android dan web.

Cara kerja integrasi Pihak Pengandel

Setiap integrasi Pihak Pengandel mengikuti empat langkah. Langkah A dan C berjalan di server Anda; Langkah B berjalan di aplikasi Android atau browser Anda. Pilih langkah mana pun untuk langsung melihat detail penerapannya:

Membangun dan menguji di sandbox sebelum meminta kredensial produksi

Saat menerapkan Langkah A–D, gunakan aset sandbox yang telah dipercaya Google agar Anda dapat langsung membangun dan menguji:

Penandatanganan Permintaan

Tanda tangani permintaan OpenID4VP menggunakan Kunci & Metadata Pengujian Sandbox Google.

Kredensial Pengujian

Lakukan pengujian di perangkat Android dalam mode Sandbox dengan Tanda Pengenal Digital Pengujian Utopia.

Validasi Respons

Validasi issuerAuth terhadap sertifikat Utopia Sandbox.

Urutan menyeluruh antara server backend, aplikasi klien atau browser, dan Google Wallet untuk verifikasi online

Format, Kredensial & Kemampuan yang Didukung

Google Wallet mendukung Tanda Pengenal Digital berbasis ISO mdoc melalui OpenID4VP (Versi 1.0) di Android 9 (level API 28) dan yang lebih tinggi serta di seluruh browser yang didukung.

Kredensial & Atribut yang Didukung

Cari ID doctype_value (mDL, tanda pengenal digital, Tanda Pengenal Berfoto) dan jalur klaim atribut yang dapat Anda minta dari Google Wallet.

Penerbit & Sertifikat IACA yang Didukung

Download root certificate IACA resmi untuk negara bagian AS, penerbit internasional, dan penerbit Sandbox Utopia untuk memvalidasi issuerAuth.


Langkah A: Memformat & Menandatangani Permintaan (Sisi Server)

Untuk meminta kredensial dari dompet mana pun, Anda harus memformat permintaan menggunakan OpenID4VP di server Anda. Anda dapat meminta kredensial tertentu atau beberapa kredensial dalam satu objek dcql_query.

Contoh Permintaan JSON

Berikut adalah contoh permintaan requestJson mdoc untuk mendapatkan kredensial identitas dari dompet mana pun di perangkat Android atau web.

{
      "requests" : [
        {
          "protocol": "openid4vp-v1-signed",
          "data": {<signed_credential_request>} // This is an object, shouldn't be a string.
        }
      ]
}

Enkripsi Permintaan

client_metadata berisi kunci publik enkripsi untuk setiap permintaan. Anda harus menyimpan kunci pribadi untuk setiap permintaan dan menggunakannya untuk mengautentikasi dan mengizinkan token yang Anda terima dari aplikasi dompet.

Metadata OpenID4VP Terintegrasi

Saat memformat permintaan kredensial, Anda harus menyertakan kolom gw_rp_metadata_bytes di dalam objek client_metadata (seperti yang ditunjukkan dalam contoh kode permintaan di bawah). Kolom ini berisi metadata pihak tepercaya berenkode Base64URL yang diperlukan oleh Google Wallet untuk memverifikasi identitas Anda dan menampilkan branding Anda kepada pengguna.

Payload Permintaan Kredensial

Parameter credential_request di requestJson berisi kolom berikut.

Kredensial Tertentu

{
  "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": {
          // Use org.iso.18013.5.1.mDL for mDL,
          // com.google.wallet.idcard.1 for ID pass, or
          // org.iso.23220.photoid.1 for ID pass (using photo ID document type)
          "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
          }
        ]
      }
    ]
  },
  "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
        ],
        "issuerauth_alg_values": [
          -7
        ]
      }
    },
    "gw_rp_metadata_bytes": "<base64url encoded metadata string>"
  }
}

Kredensial yang Memenuhi Syarat

Berikut adalah contoh permintaan untuk mDL, tanda pengenal digital, dan tanda pengenal digital (menggunakan jenis dokumen tanda pengenal berfoto). Pengguna dapat melanjutkan dengan salah satunya.

{
  "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 pass
        "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 type 3: ID pass (using photo ID document type)
        "id": "photo_id-request",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.23220.photoid.1"
        },
        "claims": [
          {
            "path": [
              "org.iso.23220.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.23220.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.23220.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      }
    ]
    credential_sets : [
      {
        "options": [
          [ "mdl-request" ],
          [ "id_pass-request" ],
          [ "photo_id-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
        ],
        "issuerauth_alg_values": [
          -7
        ]
      }
    },
    "gw_rp_metadata_bytes": "<base64url encoded metadata string>"
  }
}

Anda dapat meminta sejumlah atribut yang didukung dari kredensial identitas apa pun yang disimpan di Google Wallet.

Permintaan Bertanda Tangan

Permintaan Bertanda Tangan (JWT Secured Authorization Requests) mengenkapsulasi permintaan presentasi yang dapat diverifikasi di dalam Token Web JSON (JWT) yang ditandatangani secara kriptografis menggunakan infrastruktur PKI Anda, sehingga memastikan integritas permintaan dan membuktikan identitas Anda kepada Google Wallet.

Prasyarat

Sebelum menerapkan perubahan kode untuk permintaan bertanda tangan, pastikan Anda memiliki:

  • Kunci Pribadi: Anda memerlukan kunci pribadi (misalnya, Elliptic Curve ES256) untuk menandatangani permintaan, yang dikelola di server Anda. Untuk pengujian sandbox sebagai Pihak Penyalur, gunakan Kunci Pribadi Pengujian Sandbox.
  • Sertifikat: Anda memerlukan sertifikat X.509 standar yang berasal dari pasangan kunci Anda.
  • Pendaftaran: Pastikan sertifikat publik Anda (atau Root CA untuk Registrar Pemverifikasi) dipercaya oleh Google Wallet.

Logika Konstruksi Permintaan

Saat membuat dan menandatangani permintaan OpenID4VP, perhatikan baik-baik format encoding yang diharapkan untuk setiap kolom—mencampuradukkan base64 dan base64url atau padding (=) akan menyebabkan validasi tanda tangan atau asal gagal:

Kolom Encoding / Format yang Diperlukan Karakter & Padding
client_id (x509_hash:<hash>) base64url tanpa padding Menggunakan alfabet yang aman untuk URL (-, _); menghapus = di akhir
expected_origins (android:apk-key-hash:<hash>) Base64 standar tanpa padding Menggunakan alfabet standar (+, /); menghapus = di akhir
expected_origins (https://...) URL huruf kecil tanpa garis miring di akhir Contoh: https://example.com (tanpa / di akhir)
Header JWS x5c Base64 standar dengan padding Menggunakan alfabet standar (+, /); mempertahankan padding = di akhir

Untuk membuat permintaan, gunakan kunci pribadi Anda dan gabungkan payload dalam JWS:

def construct_openid4vp_request(
    doctypes: list[str],
    requested_fields: list[dict],
    nonce_base64: str,
    jwe_encryption_public_jwk: jwk.JWK,
    is_zkp_request: bool,
    is_signed_request: bool,
    state: dict,
    origin: str
) -> dict:

    # ... [Existing logic to build 'presentation_definition' and basic 'request_payload'] ...

    # ------------------------------------------------------------------
    # SIGNED REQUEST IMPLEMENTATION (JAR)
    # ------------------------------------------------------------------
    if is_signed_request:
        try:
            # 1. Load the Verifier's Certificate
            # We must load the PEM string into a cryptography x509 object
            verifier_cert_obj = x509.load_pem_x509_certificate(
                CERTIFICATE.encode('utf-8'),
                backend=default_backend()
            )

            # 2. Calculate Client ID (x509_hash)
            # We calculate the SHA-256 hash of the DER-encoded certificate.
            cert_der = verifier_cert_obj.public_bytes(serialization.Encoding.DER)
            verifier_fingerprint_bytes = hashlib.sha256(cert_der).digest()

            # Important: Use URL-safe Base64 (base64url: '-', '_') without padding ('=') for client_id
            verifier_fingerprint_b64 = base64.urlsafe_b64encode(verifier_fingerprint_bytes).decode('utf-8').rstrip("=")

            # Format the client_id as required by the spec
            client_id = f'x509_hash:{verifier_fingerprint_b64}'

            # 3. Update Request Payload with JAR specific fields
            request_payload["client_id"] = client_id

            # Explicitly set expected origins to prevent relay attacks
            # Important: Use standard Base64 (not URL-safe) without padding for android:apk-key-hash:
            # origin = f"android:apk-key-hash:{base64.b64encode(apk_cert_hash).decode('utf-8').rstrip('=')}"
            # Format for web origin (lowercase URL without trailing slash): origin = "https://example.com"
            if origin:
                request_payload["expected_origins"] = [origin]

            # 4. Create Signed JWT (JWS)
            # Load the signing private key
            signing_key = jwk.JWK.from_pem(PRIVATE_KEY.encode('utf-8'))

            # Initialize JWS with the JSON payload
            jws_token = jws.JWS(json.dumps(request_payload).encode('utf-8'))

            # Construct the JOSE Header
            # 'x5c' (X.509 Certificate Chain) is critical: it allows the wallet
            # to validate your key against the one registered in the console.
            # Important: Use standard Base64 ('+', '/') WITH padding ('=') for x5c
            x5c_value = base64.b64encode(cert_der).decode('utf-8')

            protected_header = {
                "alg": "ES256",                 # Algorithm (e.g., ES256 or RS256)
                "typ": "oauth-authz-req+jwt",   # Standard type for JAR
                "kid": "1",                     # Key ID
                "x5c": [x5c_value]              # Embed the certificate
            }

            # Sign the token
            jws_token.add_signature(
                key=signing_key,
                alg=None,
                protected=json_encode(protected_header)
            )

            # 5. Return the Request Object
            # Instead of returning the raw JSON, we return the signed JWT string
            # under the 'request' key.
            return {"request": jws_token.serialize(compact=True)}

        except Exception as e:
            print(f"Error signing OpenID4VP request: {e}")
            return None

    # ... [Fallback for unsigned requests] ...
    return request_payload

Langkah B: Picu API (Sisi Klien)

Seluruh permintaan API harus dibuat di sisi server. Bergantung pada platformnya, teruskan JSON yang dihasilkan ke API platform.

Dalam Aplikasi (Android)

Untuk meminta kredensial identitas dari aplikasi Android Anda, ikuti langkah-langkah berikut:

Memperbarui dependensi

Dalam build.gradle project, update dependensi untuk menggunakan Credential Manager (beta):

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

Mengonfigurasi Pengelola Kredensial

Untuk mengonfigurasi dan melakukan inisialisasi objek CredentialManager, tambahkan logika yang mirip dengan berikut ini:

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

Atribut Identitas Permintaan

Alih-alih menentukan parameter individual untuk permintaan identitas, aplikasi menyediakan semuanya bersama-sama sebagai string JSON dalam CredentialOption. Credential Manager meneruskan string JSON ini ke dompet digital yang tersedia tanpa memeriksa kontennya. Setiap dompet kemudian bertanggung jawab untuk:

  • Mengurai string JSON untuk memahami permintaan identitas.
  • Menentukan kredensial tersimpannya, jika ada, yang memenuhi permintaan.

Sebaiknya partner membuat permintaan di server, bahkan untuk integrasi aplikasi Android.

Anda akan menggunakan requestJson dari Format & Tanda Tangani Permintaan sebagai request dalam panggilan fungsi GetDigitalCredentialOption().

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

Menangani respons kredensial

Setelah Anda mendapatkan respons kembali dari dompet, verifikasi apakah respons tersebut berhasil dan berisi respons 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}")
    }
}

Respons credentialJson berisi identityToken (JWT) terenkripsi, yang ditentukan oleh W3C. Aplikasi Wallet bertanggung jawab untuk membuat respons ini.

Contoh:

{
  "protocol" : "openid4vp-v1-signed",
  "data" : {
    <encrypted_response>
  }
}

Teruskan respons ini kembali ke server Anda untuk memvalidasi keasliannya. Lihat Mendekripsi & Memvalidasi Respons.

Web

Untuk meminta Kredensial Identitas menggunakan Digital Credentials API di Chrome atau browser lain yang didukung, buat permintaan berikut:

const credentialResponse = await navigator.credentials.get({
          digital : {
          requests : [
            {
              protocol: "openid4vp-v1-signed",
              data: {<credential_request>} // This is an object, shouldn't be a string.
            }
          ]
        }
      })

Kirim respons dari API ini kembali ke server Anda untuk memvalidasi respons kredensial.


Langkah C: Dekripsi & Validasi Respons (Sisi Server)

Setelah dompet menampilkan identityToken (JWT) terenkripsi, Anda harus melakukan validasi sisi server yang ketat sebelum memercayai data.

Mendekripsi Respons

Gunakan kunci pribadi yang sesuai dengan kunci publik yang dikirim dalam client_metadata permintaan untuk mendekripsi JWE. Tindakan ini akan menghasilkan vp_token.

Contoh 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 akan menghasilkan JSON vp_token yang berisi kredensial:

{
  "vp_token":
  {
    "cred1": ["<base64UrlNoPadding_encoded_credential>"] // This applies to OpenID4VP 1.0 spec.
  }
}

Merekonstruksi SessionTranscript & Memvalidasi DeviceResponse

  1. Buat SessionTranscript dari ISO/IEC 18013-5:2021 dengan struktur Handover khusus Android atau Web:
SessionTranscript = [
  null,                // DeviceEngagementBytes not available
  null,                // EReaderKeyBytes not available
  [
    "OpenID4VPDCAPIHandover",
    AndroidHandoverDataBytes   // BrowserHandoverDataBytes for Web
  ]
]

Untuk penyerahan Android dan web, gunakan nonce yang sama dengan yang Anda gunakan untuk membuat credential_request.

Android Handover

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()

Penyerahan Browser

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()

Dengan menggunakan SessionTranscript, Respons Perangkat harus divalidasi sesuai dengan ISO/IEC 18013-5:2021 klausul 9.

Validasi ini mencakup empat pemeriksaan:

  1. Periksa Sertifikat Penerbit: Ekstrak rantai sertifikat penandatanganan penerbit dari issuerAuth dan validasi berdasarkan root certificate IACA tepercaya. Lihat Penerbit & Sertifikat IACA yang Didukung (dan tambahkan sertifikat Sandbox Utopia saat menguji dengan ID pengujian sandbox).
  2. Memverifikasi tanda tangan MSO (ISO/IEC 18013-5 Pasal 9.1.2).
  3. Menghitung dan memeriksa ValueDigests untuk Elemen Data (ISO/IEC 18013-5 Pasal 9.1.2).
  4. Memverifikasi tanda tangan deviceSignature (ISO/IEC 18013-5 Pasal 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
}

Langkah D (Opsional): Verifikasi Usia yang Menjaga Privasi (ZKP)

Untuk mendukung Bukti Zero-Knowledge (misalnya, memverifikasi bahwa pengguna berusia di atas 18 tahun tanpa melihat tanggal lahir persisnya), ubah format permintaan Anda menjadi mso_mdoc_zk dan berikan konfigurasi zk_system_type yang diperlukan.

Untuk ringkasan umum tentang apa itu ZKP dan kemampuannya, lihat FAQ.

  ...
  "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": "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,
          "block_enc_hash": 4096,
          "block_enc_sig": 2945,
        }
        {
          "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,
          "block_enc_hash": 4096,
          "block_enc_sig": 2945,
        }
       ],
       "verifier_message": "challenge"
      },
     "claims": [{
         ...
      "client_metadata": {
        "jwks": {
          "keys": [ // sample request encryption key
            {
              ...

Anda akan mendapatkan bukti zero-knowledge terenkripsi dari dompet. Anda dapat memvalidasi bukti ini terhadap sertifikat IACA penerbit menggunakan library longfellow-zk Google.

verifier-service berisi server berbasis Docker yang siap di-deploy dan memungkinkan Anda memvalidasi respons terhadap sertifikat IACA penerbit.

Anda dapat mengubah certs.pem untuk mengelola sertifikat penerbit IACA yang ingin Anda percayai.


SDK, Implementasi Referensi & Dukungan

Gunakan library open source, server referensi, dan alat verifikasi web kami untuk mempercepat implementasi Anda:

Resource / Library Yang disediakan alat ini Link
Implementasi Referensi Pemverifikasi Identitas Server dan klien contoh yang menunjukkan pembuatan permintaan OpenID4VP, penandatanganan JWS, dekripsi JWE, dan validasi respons mdoc. Repositori GitHub
Multipaz SDK Library open source (OpenWallet Foundation) termasuk DeviceResponseParser untuk decoding CBOR, rekonstruksi SessionTranscript, dan validasi tanda tangan ISO/IEC 18013-5/7. openwallet-foundation/multipaz
Library ZKP & Layanan Verifier Longfellow Library open source dan server berbasis Docker untuk memverifikasi pernyataan atribut dan usia Zero-Knowledge Proof (mso_mdoc_zk). google/longfellow-zk
Alat Verifikasi Web Interaktif Pemverifikasi web yang dihosting untuk menguji permintaan W3C Digital Credentials API / OpenID4VP terhadap Google Wallet. verifier.multipaz.org
Spesifikasi OpenID4VP 1.0 Spesifikasi protokol OpenID resmi untuk Verifiable Presentations 1.0. Spesifikasi OpenID4VP
FAQ & Dukungan Developer Jawaban atas pertanyaan umum terkait integrasi teknis, atau kirim email ke wallet-identity-rp-support@google.com untuk mendapatkan bantuan proses debug. FAQ Integrasi Teknis

Langkah berikutnya