เรายอมรับบัตรประจำตัวดิจิทัลทั้งในขั้นตอนในแอป และบนเว็บ หากต้องการยอมรับข้อมูลเข้าสู่ระบบจาก Google Wallet คุณจะต้องดำเนินการต่อไปนี้
- ผสานรวมโดยใช้แอปหรือเว็บตามวิธีการที่ระบุ
- ใช้บัตรประจำตัวทดสอบเพื่อทดสอบขั้นตอนการทำงานในแซนด์บ็อกซ์ของ Google Wallet
- เมื่อพร้อมที่จะเผยแพร่แล้ว ให้กรอกแบบฟอร์มนี้เพื่อขอและยอมรับข้อกำหนดในการให้บริการของการยอมรับข้อมูลเข้าสู่ระบบจาก Google Wallet คุณต้องกรอกข้อมูลนี้สำหรับนิติบุคคลแต่ละแห่ง
- หากมีข้อสงสัย โปรดติดต่อ
wallet-identity-rp-support@google.com
ข้อกำหนดเบื้องต้น
หากต้องการทดสอบการแสดงบัตรประจำตัวแบบดิจิทัล คุณต้องลงทะเบียนเข้าร่วมโปรแกรมเบต้าแบบสาธารณะ โดยใช้บัญชีทดสอบที่ต้องการ (ต้องเป็นบัญชี Gmail) ก่อน จากนั้นให้รายละเอียดที่ตามมาแก่ผู้ติดต่อที่กำหนดของ Google
- ลิงก์ข้อกำหนดในการให้บริการ
- โลโก้
- เว็บไซต์
- รหัสแพ็กเกจแอป (สำหรับการผสานรวมแอป Android)
- รวมถึงบิลด์สำหรับนักพัฒนาแอป / การแก้ไขข้อบกพร่อง
- ลายเซ็นแอป
$ $ANDROID_SDK/build-tools/$BUILD_TOOLS_VERSION/apksigner verify --print-certs -v $APK
- รหัส Gmail ที่ใช้เข้าร่วมเวอร์ชันเบต้าแบบเปิด
รูปแบบข้อมูลเข้าสู่ระบบที่รองรับ
มีมาตรฐานที่เสนอหลายรายการซึ่งกำหนดรูปแบบข้อมูลของเอกสารระบุตัวตนดิจิทัล โดยมี 2 รายการที่ได้รับความนิยมอย่างมากในอุตสาหกรรม ได้แก่
- mdocs - กำหนดโดย ISO
- ข้อมูลเข้าสู่ระบบที่ตรวจสอบได้ของ W3C - กำหนดโดย W3C
แม้ว่าเครื่องมือจัดการข้อมูลเข้าสู่ระบบของ Android จะรองรับทั้ง 2 รูปแบบ แต่ปัจจุบัน Google Wallet รองรับเฉพาะบัตรประจำตัวดิจิทัลที่อิงตาม mdoc
ข้อมูลเข้าสู่ระบบที่รองรับ
Google Wallet รองรับข้อมูลเข้าสู่ระบบ 2 ประเภท ได้แก่
- ใบขับขี่ดิจิทัล (mDL)
- บัตรประจำตัว
คุณขอข้อมูลเข้าสู่ระบบอย่างใดอย่างหนึ่งในโฟลว์ได้โดยเปลี่ยนพารามิเตอร์เพียงรายการเดียว
ประสบการณ์ของผู้ใช้
ส่วนนี้จะกล่าวถึงขั้นตอนการนำเสนอออนไลน์ที่แนะนำ โฟลว์แสดงการระบุอายุต่อแอปสำหรับการนำส่งเครื่องดื่มแอลกอฮอล์ แต่ UX จะคล้ายกันสำหรับเว็บและรูปแบบการนำเสนออื่นๆ
![]() |
![]() |
![]() |
![]() |
![]() |
ระบบแจ้งให้ผู้ใช้ยืนยันอายุในแอปหรือเว็บไซต์ | ผู้ใช้เห็นข้อมูลเข้าสู่ระบบที่มีสิทธิ์ | ผู้ใช้เห็นหน้ายืนยันใน Google Wallet | ผู้ใช้ตรวจสอบสิทธิ์เพื่อยืนยันการแชร์ | ข้อมูลที่ส่งไปยังแอปหรือเว็บไซต์ |
หมายเหตุสำคัญ
- แอปหรือเว็บไซต์มีความยืดหยุ่นในการสร้างจุดแรกเข้าสู่ API ดังที่แสดงในขั้นตอนที่ 1 เราขอแนะนำให้แสดงปุ่มทั่วไป เช่น "ยืนยัน ด้วยบัตรประจำตัวดิจิทัล" เนื่องจากเราคาดว่าในอนาคตตัวเลือกอื่นๆ นอกเหนือจาก Google Wallet จะพร้อมใช้งานผ่าน API
- หน้าจอตัวเลือกในขั้นตอนที่ 2 แสดงโดย Android ระบบจะพิจารณาข้อมูลเข้าสู่ระบบที่มีสิทธิ์ โดยการจับคู่ระหว่างตรรกะการลงทะเบียนที่ Wallet แต่ละรายการระบุ กับคำขอที่ส่งโดยผู้ให้บริการที่เชื่อถือได้
- ขั้นตอนที่ 3 แสดงโดย Google Wallet Google Wallet จะแสดงชื่อ โลโก้ และนโยบายความเป็นส่วนตัวที่นักพัฒนาแอประบุไว้ในหน้าจอนี้
เพิ่มโฟลว์บัตรประจำตัวดิจิทัล
ในกรณีที่ผู้ใช้ไม่มีข้อมูลเข้าสู่ระบบ เราขอแนะนำให้ระบุลิงก์ ข้างปุ่ม "ยืนยันด้วยบัตรประจำตัวดิจิทัล" ซึ่งจะลิงก์ไปยัง Google Wallet โดยตรงเพื่อให้ผู้ใช้เพิ่มบัตรประจำตัวดิจิทัลได้
![]() |
![]() |
ระบบแจ้งให้ผู้ใช้ยืนยันอายุในแอปหรือเว็บไซต์ | ผู้ใช้จะถูกนำไปยัง Google Wallet เพื่อรับบัตรประจำตัวดิจิทัล |
ไม่มีบัตรประจำตัวดิจิทัล
หากผู้ใช้เลือกตัวเลือก "ยืนยันด้วยบัตรประจำตัวดิจิทัล" โดยที่ไม่มีบัตรประจำตัวดิจิทัล ระบบจะแสดงข้อความแสดงข้อผิดพลาดนี้
![]() |
![]() |
ระบบแจ้งให้ผู้ใช้ยืนยันอายุในแอปหรือเว็บไซต์ | ระบบจะแสดงข้อผิดพลาดแก่ผู้ใช้ที่ไม่มีบัตรประจำตัวดิจิทัล |
API ไม่รองรับฟีเจอร์ที่จะเรียนรู้โดยอัตโนมัติว่าผู้ใช้มีบัตรประจำตัวดิจิทัลที่พร้อมใช้งานหรือไม่ เพื่อรักษาความเป็นส่วนตัวของผู้ใช้ ดังนั้น เราขอแนะนำให้ รวมตัวเลือกลิงก์การเริ่มต้นใช้งานตามที่แสดง
รูปแบบคำขอสำหรับการขอข้อมูลเข้าสู่ระบบบัตรประจำตัวจากกระเป๋าเงิน
นี่คือตัวอย่างคำขอ mdoc requestJson
เพื่อรับข้อมูลเข้าสู่ระบบสำหรับระบุตัวตน
จากกระเป๋าเงินใดก็ได้ในอุปกรณ์ Android หรือเว็บ
{
"requests" : [
{
"protocol": "openid4vp",
"data": {<credential_request>} // This is an object, shouldn't be a string.
}
]
}
ขอการเข้ารหัส
client_metadata
มีคีย์สาธารณะสำหรับการเข้ารหัสสำหรับคำขอแต่ละรายการ
คุณจะต้องจัดเก็บคีย์ส่วนตัวสำหรับคำขอแต่ละรายการและใช้เพื่อตรวจสอบสิทธิ์
และให้สิทธิ์โทเค็นที่คุณได้รับจากแอป Wallet
พารามิเตอร์ credential_request
ใน requestJson
จะประกอบด้วยฟิลด์ต่อไปนี้
{
"response_type": "vp_token",
"response_mode": "dc_api.jwt",
"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"
]
},
{
"path": [
"org.iso.18013.5.1",
"given_name"
]
},
{
"path": [
"org.iso.18013.5.1",
"age_over_18"
]
}
]
}
]
},
"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",
"alg" : "ECDH-ES",
}
]
},
"authorization_encrypted_response_alg": "ECDH-ES",
"authorization_encrypted_response_enc": "A128GCM"
}
}
คุณขอแอตทริบิวต์ที่รองรับ จากข้อมูลประจำตัวที่จัดเก็บไว้ใน Google Wallet ได้ไม่จำกัดจำนวน
ในแอป
หากต้องการขอข้อมูลเข้าสู่ระบบเพื่อยืนยันตัวตนจากแอป Android ให้ทำตามขั้นตอนต่อไปนี้
อัปเดตทรัพยากร Dependency
ใน build.gradle ของโปรเจ็กต์ ให้อัปเดตทรัพยากร Dependency เพื่อ ใช้ Credential Manager (เบต้า) ดังนี้
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")
}
กำหนดค่าเครื่องมือจัดการข้อมูลเข้าสู่ระบบ
หากต้องการกำหนดค่าและเริ่มต้นออบเจ็กต์ CredentialManager
ให้เพิ่มตรรกะที่คล้ายกับ
รายการต่อไปนี้
// Use your app or activity context to instantiate a client instance of CredentialManager.
val credentialManager = CredentialManager.create(context)
แอตทริบิวต์อัตลักษณ์ของคำขอ
แทนที่จะระบุพารามิเตอร์แต่ละรายการสำหรับคำขอข้อมูลประจำตัว แอป จะระบุพารามิเตอร์ทั้งหมดเป็นสตริง JSON ภายใน CredentialOption เครื่องมือจัดการข้อมูลเข้าสู่ระบบจะส่งสตริง JSON นี้ไปยังกระเป๋าเงินดิจิทัลที่พร้อมใช้งานโดยไม่ต้องตรวจสอบเนื้อหา จากนั้นกระเป๋าเงินแต่ละใบจะมีหน้าที่ดังนี้ - แยกวิเคราะห์สตริง JSON เพื่อทำความเข้าใจคำขอระบุตัวตน - การพิจารณาว่าข้อมูลเข้าสู่ระบบที่จัดเก็บไว้รายการใด (หากมี) ตรงตามคำขอ
เราขอแนะนำให้พาร์ทเนอร์สร้างคำขอในเซิร์ฟเวอร์แม้ว่าจะเป็นการผสานรวมแอป Android ก็ตาม
คุณจะใช้ requestJson
จากรูปแบบคำขอ
ซึ่งประกอบด้วย request
ในการเรียกใช้ฟังก์ชัน 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)
}
}
ยืนยันและตรวจสอบคำตอบ
เมื่อได้รับคำตอบจากกระเป๋าเงินแล้ว คุณจะยืนยันว่าคำตอบนั้นสำเร็จและมีคำตอบ 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
การตอบกลับมี identityToken (JWT) ที่เข้ารหัส
ซึ่งกำหนดโดย W3C แอป Wallet มีหน้าที่สร้างคำตอบนี้
ตัวอย่าง
{
"protocol" : "openid4vp",
"data" : {
<encrpted_response>
}
}
คุณจะส่งการตอบกลับนี้กลับไปยังเซิร์ฟเวอร์เพื่อตรวจสอบความถูกต้อง คุณดูขั้นตอนในการตรวจสอบการตอบกลับของข้อมูลเข้าสู่ระบบได้
เว็บ
หากต้องการขอข้อมูลเข้าสู่ระบบประจำตัวโดยใช้ Digital Credentials API ใน Chrome คุณจะต้องลงชื่อสมัครใช้ช่วงทดลองใช้จากต้นทางของ Digital Credentials API
const credentialResponse = await navigator.credentials.get({
digital : {
requests : [
{
protocol: "openid4vp",
data: {<credential_request>} // This is an object, shouldn't be a string.
}
]
}
})
ส่งการตอบกลับจาก API นี้กลับไปยังเซิร์ฟเวอร์เพื่อตรวจสอบความถูกต้องของข้อมูลเข้าสู่ระบบ response
ขั้นตอนในการตรวจสอบการตอบกลับของข้อมูลเข้าสู่ระบบ
เมื่อได้รับ 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) # 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_token
JSON ที่มี ข้อมูลเข้าสู่ระบบ{ "vp_token": { "cred1": "<credential_token>" } }
สร้างข้อความถอดเสียงของเซสชัน
ขั้นตอนถัดไปคือการสร้าง SessionTranscript จาก ISO/IEC 18013-5:2021 ด้วยโครงสร้างการส่งต่อที่เฉพาะเจาะจงสำหรับ Android หรือเว็บ
SessionTranscript = [ null, // DeviceEngagementBytes not available null, // EReaderKeyBytes not available [ "OpenID4VPDCAPIHandover", AndroidHandoverDataBytes // BrowserHandoverDataBytes for Web ] ]
สำหรับการส่งต่อทั้งใน Android และเว็บ คุณจะต้องใช้ Nonce เดียวกันกับที่ใช้สร้าง
credential_request
การส่งต่อใน Android
AndroidHandoverData = [ origin, // "android:apk-key-hash:<base64SHA256_ofAppSigningCert>", clientId, // "android-origin:<app_package_name>", nonce, // nonce that was used to generate credential request ] AndroidHandoverDataBytes = hashlib.sha256(cbor2.dumps(AndroidHandoverData)).digest()
การส่งต่อเบราว์เซอร์
BrowserHandoverData =[ origin, // Origin URL clientId, // "web-origin:<origin>" nonce, // nonce that was used to generate credential request ] BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
การใช้
SessionTranscript
ต้องตรวจสอบ DeviceResponse ตาม ข้อ 9 ของ ISO/IEC 18013-5:2021 ซึ่งประกอบด้วยหลายขั้นตอน เช่นตรวจสอบใบรับรองผู้ออกบัตรของรัฐ ดูใบรับรอง IACA ของผู้ออกบัตรที่รองรับ
ยืนยันลายเซ็น MSO (18013-5 ส่วนที่ 9.1.2)
คำนวณและตรวจสอบ ValueDigests สำหรับองค์ประกอบข้อมูล (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
}
ทดสอบโซลูชัน
หากต้องการทดสอบโซลูชัน ให้สร้างและเรียกใช้ที่เก็บข้อมูลอ้างอิงแบบโอเพนซอร์ส แอปพลิเคชัน Android ขั้นตอนการสร้างและเรียกใช้แอปที่เก็บข้อมูลอ้างอิงมีดังนี้
- โคลนที่เก็บแอปอ้างอิง
- เปิดโปรเจ็กต์ใน Android Studio
- สร้างและเรียกใช้เป้าหมาย
appholder
ในอุปกรณ์ Android หรือโปรแกรมจำลอง
การยืนยันโดยใช้ Zero Knowledge Proof (ZKP)
การพิสูจน์แบบไม่เปิดเผยความรู้ (Zero-Knowledge Proof หรือ ZKP) เป็นวิธีการเข้ารหัสที่ช่วยให้บุคคล (ผู้พิสูจน์) พิสูจน์ต่อผู้ตรวจสอบได้ว่าตนมีข้อมูลระบุตัวตนบางอย่างหรือเป็นไปตามเกณฑ์ที่เฉพาะเจาะจง (เช่น อายุมากกว่า 18 ปี มีข้อมูลรับรองที่ถูกต้อง) โดยไม่ต้องเปิดเผยข้อมูลพื้นฐานที่แท้จริง โดยพื้นฐานแล้ว การยืนยันตัวตนคือวิธีในการยืนยันความจริงของคำกล่าวเกี่ยวกับตัวตนของบุคคล ในขณะที่ยังคงเก็บรายละเอียดที่ละเอียดอ่อนไว้เป็นส่วนตัว
ระบบข้อมูลประจำตัวดิจิทัลที่อาศัยการแชร์ข้อมูลประจำตัวโดยตรงมัก กำหนดให้ผู้ใช้แชร์ข้อมูลส่วนบุคคลมากเกินไป ซึ่งเพิ่มความเสี่ยงต่อ การละเมิดข้อมูลและการขโมยข้อมูลประจำตัว ZKP เป็นการเปลี่ยนแปลงกระบวนทัศน์ที่ช่วยให้ การยืนยันโดยมีการเปิดเผยข้อมูลน้อยที่สุด
แนวคิดหลักของ ZKP ในบัตรประจำตัวดิจิทัล
- ผู้พิสูจน์: บุคคลที่พยายามพิสูจน์แง่มุมของตัวตน
- ผู้ยืนยัน: หน่วยงานที่ขอหลักฐานของแอตทริบิวต์ข้อมูลประจำตัว
- การพิสูจน์: โปรโตคอลการเข้ารหัสที่ช่วยให้ผู้พิสูจน์โน้มน้าว ผู้ยืนยันให้เชื่อว่าคำกล่าวอ้างของตนเป็นความจริงโดยไม่ต้องเปิดเผยข้อมูลลับ
คุณสมบัติหลักของการพิสูจน์แบบไม่เปิดเผยความรู้
- ความสมบูรณ์: หากข้อความนั้นเป็นจริงและทั้งผู้พิสูจน์และผู้ตรวจสอบมีความซื่อสัตย์ ผู้ตรวจสอบจะเชื่อ
- ความสมเหตุสมผล: หากข้อความนั้นเป็นเท็จ ผู้พิสูจน์ที่ไม่ซื่อสัตย์จะไม่สามารถ (มีความเป็นไปได้สูงมาก) โน้มน้าวผู้ตรวจสอบที่ซื่อสัตย์ว่าข้อความนั้นเป็นจริง
- ความรู้เป็นศูนย์: ผู้ตรวจสอบจะไม่ทราบอะไรเลยนอกเหนือจากข้อเท็จจริงที่ว่าคำสั่งเป็นจริง โดยจะไม่มีการเปิดเผยข้อมูลจริงจากตัวตนของผู้พิสูจน์
หากต้องการรับการพิสูจน์แบบ Zero Knowledge จาก Google Wallet คุณต้องเปลี่ยนรูปแบบคำขอเป็น 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
}
],
"verifier_message": "challenge"
},
"claims": [{
...
"client_metadata": {
"jwks": {
"keys": [ // sample request encryption key
{
...
คุณจะได้รับหลักฐานแบบปกปิดข้อมูลที่เข้ารหัสกลับจากกระเป๋าเงิน คุณสามารถ
ตรวจสอบความถูกต้องของหลักฐานนี้กับใบรับรอง IACA ของผู้ออกโดยใช้ไลบรารี longfellow-zk ของ Google
คุณติดต่ออีเมลสนับสนุนเพื่อขอรายละเอียดเพิ่มเติมได้
wallet-identity-rp-support@google.com