線上活動
數位 ID 可用於應用程式內和網站流程。如要接受 Google 錢包的憑證,您必須:
- 按照提供的指示,使用應用程式或網頁進行整合,
- 請填寫這份表單,申請並同意接受 Google 錢包憑證的服務條款。
必要條件
如要測試 ID 呈現方式,您必須先使用指定的測試帳戶註冊公開 Beta 版計畫。接著,請將下列詳細資料提供給指定的 Google 聯絡窗口。
- 服務條款連結
- 標誌
- 網站
- Play 商店套件 ID (適用於 Android 應用程式整合)
- 用於加入公開測試的 Gmail ID
支援的憑證格式
目前有幾項標準定義了數位身分證件資料格式,其中兩項已獲得業界廣泛採用:
雖然 Android 憑證管理工具支援這兩種格式,但 Google 錢包目前僅支援以 mdoc 為基礎的數位身分證件。
使用者體驗
應用程式要求身分屬性時,會發生以下程序:
憑證探索:應用程式會查詢可用的錢包,找出可滿足要求的憑證。接著,Android 會顯示系統 UI 選取器,顯示要共用的資訊。這樣一來,使用者就能根據自身情況決定要使用的憑證。
使用者選取項目和錢包互動:使用者選取憑證後,Android 會叫用對應的錢包應用程式,以完成交易。錢包應用程式可能會顯示自己的同意畫面,或要求使用生物特徵辨識功能進行確認。
結果:如果使用者同意,系統就會將所選身分證件憑證分享給要求的應用程式。如果使用者拒絕,系統會傳回錯誤。
應用程式內
如要從 Android 應用程式要求身分憑證,請按照下列步驟操作:
更新依附元件
在專案的 build.gradle 檔案中更新依附元件,以便使用 Credential Manager (Beta 版):
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)
要求身分屬性
應用程式不會為身分識別要求指定個別參數,而是會在 CredentialOption 中以 JSON 字串的形式提供所有參數。憑證管理工具會將這個 JSON 字串傳送至可用的數位錢包,但不會檢查其內容。每個錢包都必須負責: - 剖析 JSON 字串,以便瞭解身分要求。- 判斷儲存的憑證 (如有) 是否符合要求。
預期 W3C 會將此 JSON 要求的結構定義為網路 API 規格的一部分。不過,請務必注意,規格為草稿形式,可能會有所變動。
我們一開始會使用預先發布版的通訊協定,從 Google 錢包取得 ID。這樣我們就能在 Web API 規格定案時開始整合及測試。
以下是預覽通訊協定 mdoc requestJson
的範例:
{
identity: {
providers: [{
holder: {
selector: {
format: ['mdoc'],
type: 'org.iso.18013.5.1.mDL',
fields: [
'org.iso.18013.5.1.family_name',
'org.iso.18013.5.1.portrait',
]
},
params: {
nonce: '1234',
readerPublicKey: '<public_key>',
extraParamAsNeededByWallets: true,
},
},
}]
}
}
// 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)
}
}
// 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}")
}
}
回應會傳回 W3C 定義的 identityToken (JSON 字串)。錢包應用程式會負責建立此回應。
範例:
{
"token": "<base64 encoded response>"
}
在伺服器上傳送權杖和處理程序
收到 identityToken 後,應用程式應將其傳送至應用程式伺服器進行驗證。初始步驟包括從 base64 格式解碼符記。產生的位元組陣列代表 CBOR 資料,且會遵循下列 CDDL。
CredentialDocument = {
"version": tstr, // Set to "ANDROID-HPKE-v1"
"pkEm": bstr, // Public key, in uncompressed form
"cipherText": bstr // The encrypted data
}
接下來,我們將使用 Android 專屬的 Handover 結構體,根據 ISO/IEC 18013-5:2021 計算 SessionTranscript:
SessionTranscript = [
null, // DeviceEngagementBytes not available
null, // EReaderKeyBytes not available
AndroidHandover // Defined below
]
AndroidHandover = [
"AndroidHandoverv1", // Version number
nonce, // nonce that comes from request
appId, // RP package name
pkRHash, // The SHA256 hash of the recipient public key
]
cipherText 會使用 HPKE 加密。如要解密,請使用 SessionTranscript 做為額外已驗證資料,搭配先前產生的 EC 私密金鑰,以及下列設定:
- KEM:DHKEM(P-256, HKDF-SHA256)
- KDF:HKDF-SHA256
- AEAD:AES-128-GCM
產生的明文是 ISO/IEC 18013-5:2021 中定義的 DeviceResponse CBOR 位元組。DeviceResponse 必須依據 ISO/IEC 18013-5:2021 的第 9 節進行驗證。這包括幾個步驟,例如驗證 mdoc 是否來自可信任的發證機構,以及回應是否由指定裝置簽署。OpenWallet Foundation Identity Credential 專案的 DeviceResponseParser 類別可用於驗證程序的某個部分。
網頁
如要在 Chrome 上使用 Digital Credentials API 要求身分憑證,您必須註冊 Digital Credentials API 來源試用。
現場活動
如要接受 Google 錢包中的身分證件,請完成下列步驟:
- 建構或取得讀取器,以便接受 ISO 18013-5 定義的 ID
- 將 IACA 憑證載入讀取器,確保系統接受的身分證件為真
- 測試解決方案
- 將應用程式註冊至 Google 錢包
建構或取得讀取器,以便接受 ISO 18013-5 定義的 ID
錢包中的身分證件是根據 ISO 18013-5 行動駕照標準實作。這些標準使用 NFC 或 QR code 互動功能,並搭配 BLE 做為資料傳輸機制,因此任何可實作這些標準的裝置都能充當讀取器,甚至是行動應用程式。由於標準是開放的,因此市場上有幾種第三方實作方式可供選擇。您也可以視需要直接實作功能。
如需自行實作這項功能的指引,請參閱我們的開源參考讀取器 Android 應用程式,該應用程式實作 ISO 標準,可接受 Google 錢包的 mDL。
您可以開始建構並執行參考讀取器應用程式:
- 複製參考應用程式存放區
- 在 Android Studio 中開啟專案
- 在 Android 裝置或模擬器上建構及執行
appverifier
目標。
將 IACA 憑證載入讀取器,確保系統接受的身分證件為真
如要驗證實體憑證,您必須在錢包中擁有支援發證機構核發的身分證件。下方列出 Google 電子錢包支援的發卡機構,以及其憑證的驗證連結。
如要測試您的解決方案,請建構並執行我們的開放原始碼參考資料持有者 Android 應用程式。以下是建構及執行參照資料容器應用程式的步驟:
- 複製參考應用程式存放區
- 在 Android Studio 中開啟專案
- 在 Android 裝置或模擬器上建構及執行
appholder
目標。
(選用) 將應用程式註冊至 Google 錢包
如要將應用程式註冊至 Google 錢包,請填寫這份表單。