Panduan Orientasi Registrar Pemverifikasi

Ringkasan

Bagian ini menguraikan proses langkah demi langkah bagi registrar verifikasi untuk mengaktifkan layanan Identitas Google Wallet.

Sebagai pendaftar verifikasi (misalnya, perusahaan IDV yang melakukan verifikasi atas nama entitas lain), Anda bertindak sebagai Otoritas Sertifikat (CA) Anda sendiri, menandatangani permintaan identitas untuk Pihak Penerima Akhir (RP) hilir yang Anda kelola.

Proses orientasi

Langkah 1: Kirim Formulir Informasi, Sertifikat Root & Setujui Persyaratan Layanan

Isi dan kirimkan Formulir Informasi Pengaktifan Lembaga Verifikasi. Dalam formulir ini, Anda akan memberikan Sertifikat Root Sandbox dan Produksi. Dengan mengirimkan formulir pengaktifan ini, Anda juga secara resmi menyetujui Persyaratan Layanan Pendaftar Verifikasi Google Wallet.

Langkah 2: Kepercayaan & Pengujian Sandbox

Setelah Anda mengirimkan formulir pendaftaran, Google akan menambahkan sertifikat root sandbox Anda ke penyimpanan tepercaya sandbox Google Wallet dan memberi tahu Anda. Kemudian, Anda dapat mulai menguji integrasi di Sandbox menggunakan sertifikat yang ditandatangani oleh root sandbox Anda.

Langkah 3: Rekam Demonstrasi Video E2E

Setelah pengujian sandbox selesai, rekam demonstrasi video end-to-end alur verifikasi untuk Pihak Tepercaya awal (ke-1) Anda dan kirimkan ke Google.

  • Persyaratan Video:
    • Rekam demonstrasi untuk alur dihosting verifier (dihosting sendiri) dan dihosting penjual (dihosting RP) sebagaimana berlaku.
    • Gunakan aset tampilan penjual sebenarnya (Nama, Logo, URL Persyaratan Layanan) dan aset tampilan agregator dalam video.
    • Tunjukkan dengan jelas antarmuka pengguna dan layar yang meluncurkan alur verifikasi.

Langkah 4: Persetujuan & Kepercayaan Root Produksi

Setelah menerima demonstrasi video end-to-end Anda, Google akan memicu proses peninjauan dan persetujuan video sekaligus memulai proses tepercaya sertifikat root produksi secara paralel. Setelah kedua proses selesai dan disetujui, Anda dapat mulai meluncurkan layanan untuk RP Hilir Anda.

Langkah 5: Orientasi Berkelanjutan untuk Mengakhiri RP

Untuk setiap RP Akhir yang Anda tanda tangani, Anda harus:

  • Memberi tahu Google: Gunakan Formulir Aktivasi Klien Registrar Verifikasi untuk memberi tahu Google tentang RP baru dan kasus penggunaannya yang dimaksud.
  • Konfigurasi Metadata: Isi informasi tampilan RP (Nama, Logo, URL Kebijakan Privasi) dan tetapkan Nama Pembeda (Subjek) yang unik secara global di sertifikatnya.

Spesifikasi teknis

A. Profil sertifikat

Permintaan harus ditandatangani oleh sertifikat X.509 v3 standar yang dibuat menggunakan P-256 / ECDSA dan berisi ekstensi Google kustom:

  • OID Ekstensi Kustom: 1.3.6.1.4.1.11129.10.1
  • Kekritisan: Tidak penting.
  • Konten: Hash SHA256 dari RelyingPartyMetadataBytes, dienkode dalam OCTET STRING ASN.1.

B. Skema metadata (CBOR)

Metadata harus dienkode dalam format CBOR.

; in CDDL for CBOR encoding
; schemaVersion = "v1"

RelyingPartyMetadataBytes = #6.24(bstr .cbor RelyingPartyMetadata)


RelyingPartyMetadata = {
  "schema_version": tstr,
  "display": DisplayInfo,
  "aggregator_info": DisplayInfo  ; Optional: include to show your branding alongside the RP
}

DisplayInfo = {
  "display_name": tstr,
  "logo_uri": tstr,             ; See brand guidelines link in following paragraph
  "privacy_policy_uri": tstr
}

logo_uri harus mengikuti Pedoman Merek Google Wallet.

C. Integrasi OpenID4VP

Saat memformat permintaan kredensial OpenID4VP bertanda tangan, sertakan metadata yang dienkode base64url di kolom gw_rp_metadata_bytes dalam objek client_metadata (seperti yang ditunjukkan dalam kode permintaan contoh di bagian berikut).

Kepatuhan dan pencabutan

  • Pemantauan Penyalahgunaan: Google memantau aktivitas RP berbahaya dan akan memberi tahu Anda jika ada penyalahgunaan yang terdeteksi.
  • Pencabutan Segera: Anda diwajibkan untuk segera mencabut sertifikat RP yang menyalahgunakan dan memublikasikan Daftar Pencabutan Sertifikat (CRL) yang telah diperbarui.
  • Audit: Google menyimpan log anonim untuk memastikan permintaan RP sesuai dengan kasus penggunaan yang terdaftar.

Langkah berikutnya

Untuk memulai aktivasi Anda sebagai Pendaftar Verifikasi, isi dan kirimkan Formulir Informasi Aktivasi Pendaftar Verifikasi. Untuk mengaktifkan klien hilir berikutnya, gunakan Formulir Aktivasi Klien Pendaftar Verifikasi.

Untuk pertanyaan umum (FAQ) tentang aktivasi dan integrasi, lihat FAQ Identitas & Kredensial Digital.

Detail Integrasi Registrar Verifikator

Bagian berikut mencakup detail integrasi teknis untuk Pendaftar Verifikasi yang terintegrasi dengan Digital Credentials API (termasuk pemformatan permintaan, enkripsi permintaan, pemicuan API, validasi respons, dan penerapan Zero-Knowledge Proof).

Format & Kemampuan yang Didukung

Google Wallet mendukung Tanda Pengenal Digital berbasis mdoc ISO.

Memformat Permintaan

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

Contoh Permintaan JSON

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

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

Meminta Enkripsi

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 kode permintaan contoh di bawah). Kolom ini berisi metadata pihak tepercaya yang dienkode Base64URL yang diperlukan oleh Google Wallet untuk memverifikasi identitas Anda dan menampilkan branding Anda kepada pengguna.

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": {
          "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
        ],
        "issuerauth_alg_values": [
          -7
        ]
      }
    },
    "gw_rp_metadata_bytes": "<base64url encoded metadata string>"
  }
}

Kredensial yang Memenuhi Syarat

Berikut adalah contoh permintaan untuk mDL dan tanda pengenal digital. 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": "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
        ],
        "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 (Permintaan Otorisasi yang Diamankan dengan JWT) merangkum 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 ke Google Wallet.

Prasyarat

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

  • Kunci Pribadi: Anda memerlukan kunci pribadi (misalnya, Elliptic Curve ES256) untuk menandatangani permintaan yang dikelola di server Anda.
  • Sertifikat: Anda memerlukan sertifikat X.509 standar yang berasal dari pasangan kunci Anda.
  • Pendaftaran: Pastikan sertifikat publik Anda terdaftar di Google Wallet.

Logika Pembuatan Permintaan

Untuk membuat permintaan, Anda harus menggunakan kunci pribadi dan membungkus 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()

            # Create a URL-safe Base64 hash (removing padding '=')
            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
            # Format for android origin: origin = android:apk-key-hash:<base64SHA256_ofAppSigningCert>
            # Format for web origin: origin = <origin_url>
            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.
            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

Memicu API

Seluruh permintaan API harus dibuat di sisi server. Bergantung pada platform, Anda akan meneruskan 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, perbarui 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)

Meminta atribut Identitas

Daripada menentukan parameter satu per satu untuk permintaan identitas, aplikasi menyediakannya secara bersamaan sebagai string JSON dalam CredentialOption. Credential Manager meneruskan string JSON ini ke dompet digital yang tersedia tanpa memeriksa isinya. Setiap dompet kemudian bertanggung jawab untuk: - Mengurai string JSON untuk memahami permintaan identitas. - Menentukan kredensial tersimpan mana, jika ada, yang memenuhi permintaan.

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

Anda akan menggunakan requestJson dari Format 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 mendapatkan respons kembali dari wallet, Anda akan memverifikasi apakah respons 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" : {
    <encrpted_response>
  }
}

Anda akan meneruskan respons ini kembali ke server untuk memvalidasi keasliannya. Anda dapat menemukan langkah-langkah untuk memvalidasi respons kredensial

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.
            }
          ]
        }
      })

Kirimkan respons dari API ini kembali ke server Anda untuk memvalidasi respons kredensial

Memvalidasi Respons

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

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.
    }
  }
  1. Membuat transkrip sesi

    Langkah selanjutnya adalah membuat SessionTranscript dari ISO/IEC 18013-5:2021 dengan struktur Pengalihan khusus Android atau Web:

    SessionTranscript = [
      null,                // DeviceEngagementBytes not available
      null,                // EReaderKeyBytes not available
      [
        "OpenID4VPDCAPIHandover",
        AndroidHandoverDataBytes   // BrowserHandoverDataBytes for Web
      ]
    ]
    

    Untuk peralihan Android dan web, Anda harus menggunakan nonce yang sama dengan yang Anda gunakan untuk membuat credential_request.

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

    Pengalihan 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 klausul 9 ISO/IEC 18013-5:2021.

    Validasi ini mencakup beberapa langkah:

  2. Periksa Sertifikat Penerbit: Ekstrak rantai sertifikat penandatangan penerbit dari issuerAuth dan validasi terhadap sertifikat root IACA tepercaya. Lihat sertifikat IACA penerbit yang didukung.

  3. Verifikasi tanda tangan MSO (18013-5 Bagian 9.1.2)

  4. Menghitung dan memeriksa ValueDigests untuk Elemen Data (18013-5 Pasal 9.1.2)

  5. Verifikasi tanda tangan deviceSignature (18013-5 Bagian 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
}

Verifikasi Usia yang Menjaga Privasi (ZKP)

Untuk mendukung Bukti Tanpa Pengetahuan (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 tingkat tinggi 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 kembali dari wallet. 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 tertentu.

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

Referensi & Dukungan