正在接受來自 Google 錢包的身分證件

線上活動

數位 ID 可用於應用程式內網站流程。如要接受 Google 錢包的憑證,您必須:

  1. 按照提供的指示,使用應用程式或網頁進行整合,
  2. 請填寫這份表單,申請並同意接受 Google 錢包憑證的服務條款。

必要條件

如要測試 ID 呈現方式,您必須先使用指定的測試帳戶註冊公開 Beta 版計畫。接著,請將下列詳細資料提供給指定的 Google 聯絡窗口。

  • 服務條款連結
  • 標誌
  • 網站
  • Play 商店套件 ID (適用於 Android 應用程式整合)
  • 用於加入公開測試的 Gmail ID

支援的憑證格式

目前有幾項標準定義了數位身分證件資料格式,其中兩項已獲得業界廣泛採用:

  1. mdocs:由 ISO 定義。
  2. W3C 可驗證憑證:由 W3C 定義。

雖然 Android 憑證管理工具支援這兩種格式,但 Google 錢包目前僅支援以 mdoc 為基礎的數位身分證件。

使用者體驗

應用程式要求身分屬性時,會發生以下程序:

  1. 憑證探索:應用程式會查詢可用的錢包,找出可滿足要求的憑證。接著,Android 會顯示系統 UI 選取器,顯示要共用的資訊。這樣一來,使用者就能根據自身情況決定要使用的憑證。

  2. 使用者選取項目和錢包互動:使用者選取憑證後,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 錢包,請填寫這份表單