अपने होल्डर ऐप्लिकेशन को Credential Manager के साथ इंटिग्रेट करना

क्रेडेंशियल मैनेजर होल्डर एपीआई की मदद से, Android होल्डर (इसे "वॉलेट" भी कहा जाता है) ऐप्लिकेशन, डिजिटल क्रेडेंशियल को मैनेज कर सकता है और पुष्टि करने वालों को दिखा सकता है.

क्रेडेंशियल मैनेजर में डिजिटल क्रेडेंशियल का यूज़र इंटरफ़ेस (यूआई) दिखाने वाली इमेज
पहली इमेज. डिजिटल क्रेडेंशियल चुनने वाले टूल का यूज़र इंटरफ़ेस (यूआई).

सबसे ज़रूरी सिद्धांत

होल्डर एपीआई का इस्तेमाल करने से पहले, इन कॉन्सेप्ट के बारे में जानना ज़रूरी है.

क्रेडेंशियल के फ़ॉर्मैट

क्रेडेंशियल को, क्रेडेंशियल होल्डर ऐप्लिकेशन में अलग-अलग क्रेडेंशियल फ़ॉर्मैट में सेव किया जा सकता है. ये फ़ॉर्मैट, क्रेडेंशियल को दिखाने के तरीके के बारे में जानकारी देते हैं. हर फ़ॉर्मैट में, क्रेडेंशियल के बारे में यह जानकारी होती है:

  • टाइप: कैटगरी, जैसे कि यूनिवर्सिटी की डिग्री या मोबाइल ड्राइवर लाइसेंस.
  • प्रॉपर्टी: पहले और आखिरी नाम जैसे एट्रिब्यूट.
  • कोड में बदलने का तरीका: क्रेडेंशियल को स्ट्रक्चर करने का तरीका. उदाहरण के लिए, SD-JWT या mdoc
  • मान्यता: क्रेडेंशियल की प्रामाणिकता की क्रिप्टोग्राफ़िक तरीके से पुष्टि करने का तरीका.

हर क्रेडेंशियल फ़ॉर्मैट, एन्कोडिंग और पुष्टि करने की प्रोसेस को थोड़ा अलग तरीके से करता है. हालांकि, ये फ़ंक्शन एक जैसे होते हैं.

रजिस्ट्री में दो फ़ॉर्मैट इस्तेमाल किए जा सकते हैं:

क्रेडेंशियल मैनेजर का इस्तेमाल करते समय, पुष्टि करने वाला व्यक्ति SD-JWT और mdocs के लिए OpenID4VP अनुरोध कर सकता है. इस्तेमाल के उदाहरण और इंडस्ट्री के हिसाब से, विकल्प अलग-अलग होते हैं.

क्रेडेंशियल मेटाडेटा का रजिस्ट्रेशन

क्रेडेंशियल मैनेजर, क्रेडेंशियल के मालिक के क्रेडेंशियल को सीधे तौर पर सेव नहीं करता. इसके बजाय, यह क्रेडेंशियल के मेटाडेटा को सेव करता है. होल्डर ऐप्लिकेशन को सबसे पहले, RegistryManager का इस्तेमाल करके Credential Manager के साथ क्रेडेंशियल मेटाडेटा रजिस्टर करना होगा. रजिस्ट्रेशन की इस प्रोसेस से, एक रजिस्ट्री रिकॉर्ड बनता है. इससे दो मुख्य मकसद पूरे होते हैं:

  • मिलान करना: रजिस्टर किए गए क्रेडेंशियल के मेटाडेटा का इस्तेमाल, पुष्टि करने वाले व्यक्ति के आने वाले अनुरोधों से मिलान करने के लिए किया जाता है.
  • दिखाना: क्रेडेंशियल सिलेक्टर इंटरफ़ेस पर, उपयोगकर्ता को पसंद के मुताबिक बनाए गए यूज़र इंटरफ़ेस (यूआई) एलिमेंट दिखाए जाते हैं.

आपको अपने डिजिटल क्रेडेंशियल रजिस्टर करने के लिए, OpenId4VpRegistry क्लास का इस्तेमाल करना होगा. ऐसा इसलिए, क्योंकि यह mdoc और SD-JWT, दोनों तरह के क्रेडेंशियल फ़ॉर्मैट के साथ काम करती है. पुष्टि करने वाले लोग या कंपनियां, इन क्रेडेंशियल का अनुरोध करने के लिए OpenID4VP अनुरोध भेजेंगी.

अपने ऐप्लिकेशन के क्रेडेंशियल रजिस्टर करना

Credential Manager Holder API का इस्तेमाल करने के लिए, अपने ऐप्लिकेशन मॉड्यूल की बिल्ड स्क्रिप्ट में ये डिपेंडेंसी जोड़ें:

Groovy

dependencies {
    // Use to implement credentials registrys

    implementation "androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-digitalcredentials-preview:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-provider:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04"

}

Kotlin

dependencies {
    // Use to implement credentials registrys

    implementation("androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-digitalcredentials-preview:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-provider:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04")

}

RegistryManager बनाएं

RegistryManager इंस्टेंस बनाएं और उसके साथ OpenId4VpRegistry अनुरोध रजिस्टर करें.

// Create the registry manager
val registryManager = RegistryManager.create(context)

// The guide covers how to build this out later
val registryRequest = OpenId4VpRegistry(credentialEntries, id)

try {
    registryManager.registerCredentials(registryRequest)
} catch (e: Exception) {
    // Handle exceptions
}

OpenId4VpRegistry अनुरोध बनाना

जैसा कि पहले बताया गया है, आपको OpenId4VpRegistry रजिस्टर करना होगा, ताकि पुष्टि करने वाले व्यक्ति से मिले OpenID4VP अनुरोध को मैनेज किया जा सके. हम मान लेंगे कि आपने अपने वॉलेट क्रेडेंशियल के साथ कुछ स्थानीय डेटा टाइप लोड किए हैं. उदाहरण के लिए, sdJwtsFromStorage. अब आपको उन्हें उनके फ़ॉर्मैट के आधार पर, हमारे Jetpack DigitalCredentialEntry के बराबर के फ़ॉर्मैट में बदलना होगा. जैसे, एसडी-जेडब्ल्यूटी के लिए SdJwtEntry या एमडॉक के लिए MdocEntry.

रजिस्ट्री में Sd-JWT जोड़ना

रजिस्ट्री के लिए, हर लोकल एसडी-JWT क्रेडेंशियल को SdJwtEntry पर मैप करें:

fun mapToSdJwtEntries(sdJwtsFromStorage: List<StoredSdJwtEntry>): List<SdJwtEntry> {
    val list = mutableListOf<SdJwtEntry>()

    for (sdJwt in sdJwtsFromStorage) {
        list.add(
            SdJwtEntry(
                verifiableCredentialType = sdJwt.getVCT(),
                claims = sdJwt.getClaimsList(),
                entryDisplayPropertySet = sdJwt.toDisplayProperties(),
                id = sdJwt.getId() // Make sure this cannot be readily guessed
            )
        )
    }
    return list
}

mdocs को रजिस्ट्री में जोड़ना

अपने स्थानीय mdoc क्रेडेंशियल को Jetpack टाइप MdocEntry में मैप करें:

fun mapToMdocEntries(mdocsFromStorage: List<StoredMdocEntry>): List<MdocEntry> {
    val list = mutableListOf<MdocEntry>()

    for (mdoc in mdocsFromStorage) {
        list.add(
            MdocEntry(
                docType = mdoc.retrieveDocType(),
                fields = mdoc.getFields(),
                entryDisplayPropertySet = mdoc.toDisplayProperties(),
                id = mdoc.getId() // Make sure this cannot be readily guessed
            )
        )
    }
    return list
}

कोड के बारे में मुख्य बातें

  • id फ़ील्ड को कॉन्फ़िगर करने का एक तरीका यह है कि एन्क्रिप्ट (सुरक्षित) किए गए क्रेडेंशियल आइडेंटिफ़ायर को रजिस्टर किया जाए, ताकि सिर्फ़ आप वैल्यू को डिक्रिप्ट (सुरक्षित तरीके से बदलना) कर सकें.
  • दोनों फ़ॉर्मैट के लिए, यूज़र इंटरफ़ेस (यूआई) डिसप्ले फ़ील्ड को स्थानीय भाषा में होना चाहिए.

अपने क्रेडेंशियल रजिस्टर करना

कन्वर्ट की गई एंट्री को एक साथ जोड़ें और RegistryManager के साथ अनुरोध रजिस्टर करें:

val credentialEntries = mapToSdJwtEntries(sdJwtsFromStorage) + mapToMdocEntries(mdocsFromStorage)

val openidRegistryRequest = OpenId4VpRegistry(
    credentialEntries = credentialEntries,
    id = "my-wallet-openid-registry-v1" // A stable, unique ID to identify your registry record.
)

अब हम आपके क्रेडेंशियल को CredentialManager के साथ रजिस्टर करने के लिए तैयार हैं.

try {
    val response = registryManager.registerCredentials(openidRegistryRequest)
} catch (e: Exception) {
    // Handle failure
}

आपने अब क्रेडेंशियल मैनेजर में अपने क्रेडेंशियल रजिस्टर कर लिए हैं.

ऐप्लिकेशन के मेटाडेटा को मैनेज करना

क्रेडेंशियल मैनेजर के साथ रजिस्टर किए गए होल्डर ऐप्लिकेशन के मेटाडेटा में ये प्रॉपर्टी होती हैं:

  • डेटा सेव करने की अवधि: इस जानकारी को डिवाइस पर सेव किया जाता है. यह डिवाइस को रीबूट करने के बाद भी बनी रहती है.
  • अलग-अलग स्टोरेज: हर ऐप्लिकेशन के रजिस्ट्री रिकॉर्ड अलग-अलग सेव किए जाते हैं. इसका मतलब है कि कोई ऐप्लिकेशन, दूसरे ऐप्लिकेशन के रजिस्ट्री रिकॉर्ड में बदलाव नहीं कर सकता.
  • की के साथ अपडेट: हर ऐप्लिकेशन के रजिस्ट्री रिकॉर्ड को id के हिसाब से क्रम में लगाया जाता है. इससे रिकॉर्ड की फिर से पहचान करने, उन्हें अपडेट करने या मिटाने की अनुमति मिलती है.
  • मेटाडेटा अपडेट करना: जब भी आपका ऐप्लिकेशन बदलता है या पहली बार लोड होता है, तब सेव किए गए मेटाडेटा को अपडेट करना एक अच्छा तरीका है. अगर एक ही id में किसी रजिस्ट्री को कई बार कॉल किया जाता है, तो सबसे नया कॉल, पिछले सभी रिकॉर्ड को बदल देता है. अपडेट करने के लिए, पुराने रिकॉर्ड को मिटाए बिना फिर से रजिस्टर करें.

ज़रूरी नहीं: मैच करने वाला कोई फ़ंक्शन बनाना

मैचर एक Wasm बाइनरी है. Credential Manager इसे सैंडबॉक्स में चलाता है, ताकि आने वाले वेरिफ़ायर के अनुरोध के हिसाब से, आपके रजिस्टर किए गए क्रेडेंशियल को फ़िल्टर किया जा सके.

  • डिफ़ॉल्ट मैच करने वाला:OpenId4VpRegistry क्लास को इंस्टैंटिएट करने पर, डिफ़ॉल्ट OpenId4VP मैच करने वाला (OpenId4VpDefaults.DEFAULT_MATCHER) अपने-आप शामिल हो जाता है. OpenID4VP के सभी स्टैंडर्ड इस्तेमाल के उदाहरणों के लिए, लाइब्रेरी आपके लिए मैचिंग को मैनेज करती है.
  • कस्टम मैच करने वाला: कस्टम मैच करने वाले को सिर्फ़ तब लागू किया जाता है, जब आपको किसी ऐसे नॉन-स्टैंडर्ड प्रोटोकॉल के साथ काम करना हो जिसके लिए मैच करने के अपने लॉजिक की ज़रूरत होती है.

चुने गए क्रेडेंशियल को मैनेज करना

जब कोई उपयोगकर्ता क्रेडेंशियल चुनता है, तो आपके होल्डर ऐप्लिकेशन को अनुरोध को मैनेज करना होता है. आपको एक ऐसी गतिविधि तय करनी होगी जो androidx.credentials.registry.provider.action.GET_CREDENTIAL इंटेंट फ़िल्टर को सुने. हमारे सैंपल वॉलेट में इस प्रोसेस के बारे में बताया गया है.

इंटेंट, पुष्टि करने वाले के अनुरोध और कॉलिंग ओरिजिन के साथ आपकी गतिविधि शुरू करता है. PendingIntentHandler.retrieveProviderGetCredentialRequest फ़ंक्शन की मदद से, इसे एक्सट्रैक्ट किया जाता है. इससे, पुष्टि करने वाले व्यक्ति के अनुरोध से जुड़ी सभी जानकारी वाला ProviderGetCredentialRequest मिलता है. इसके तीन मुख्य कॉम्पोनेंट हैं:

  • कॉल करने वाला ऐप्लिकेशन: यह वह ऐप्लिकेशन है जिसने अनुरोध किया है. इसे getCallingAppInfo की मदद से वापस पाया जा सकता है.
  • चुना गया क्रेडेंशियल: इस बारे में जानकारी कि उपयोगकर्ता ने किस उम्मीदवार को चुना है. यह जानकारी selectedCredentialSet extension method के ज़रिए मिलती है. यह क्रेडेंशियल आईडी, आपके रजिस्टर किए गए क्रेडेंशियल आईडी से मेल खाएगा.
  • खास अनुरोध: पुष्टि करने वाले व्यक्ति ने जो खास अनुरोध किया है उसे getCredentialOptions तरीके से वापस पाया गया है. डिजिटल क्रेडेंशियल के अनुरोध वाले फ़्लो के लिए, आपको इस सूची में सिर्फ़ एक GetDigitalCredentialOption दिखेगा.

आम तौर पर, पुष्टि करने वाला व्यक्ति डिजिटल क्रेडेंशियल दिखाने का अनुरोध करता है. इस अनुरोध को प्रोसेस करने के लिए, यहां दिए गए सैंपल कोड का इस्तेमाल किया जा सकता है:

request.credentialOptions.forEach { option ->
    if (option is GetDigitalCredentialOption) {
        Log.i(TAG, "Got DC request: ${option.requestJson}")
        processRequest(option.requestJson)
    }
}

इसका उदाहरण, सैंपल वॉलेट में देखा जा सकता है.

पुष्टि करने वाले की पहचान की पुष्टि करना

  1. इंटेंट से ProviderGetCredentialRequest निकालो:
val request = PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)
  1. खास अधिकार वाले ऑरिजिन की जांच करें: खास अधिकार वाले ऐप्लिकेशन (जैसे कि वेब ब्राउज़र), ऑरिजिन पैरामीटर सेट करके, पुष्टि करने वाले अन्य लोगों की ओर से कॉल कर सकते हैं. इस ऑरिजिन को वापस पाने के लिए, आपको CallingAppInfo के getOrigin() एपीआई को, भरोसेमंद और खास अधिकारों वाले कॉलर की सूची (JSON फ़ॉर्मैट में अनुमति वाली सूची) भेजनी होगी.
val origin = request?.callingAppInfo?.getOrigin(
    privilegedAppsJson // Your allow list JSON
)

अगर ऑरिजिन खाली नहीं है, तो: ऑरिजिन तब दिखता है, जब packageName और signingInfo से मिले सर्टिफ़िकेट फ़िंगरप्रिंट, getOrigin() एपीआई को पास की गई अनुमति वाली सूची में मौजूद किसी ऐप्लिकेशन के फ़िंगरप्रिंट से मेल खाते हों. ओरिजन वैल्यू मिलने के बाद, प्रोवाइडर ऐप्लिकेशन को इसे खास कॉल मानना चाहिए. साथ ही, कॉलिंग ऐप्लिकेशन के हस्ताक्षर का इस्तेमाल करके ओरिजन का हिसाब लगाने के बजाय, OpenID4VP रिस्पॉन्स पर इस ओरिजन को सेट करना चाहिए.

Google Password Manager, getOrigin() को कॉल करने के लिए, सार्वजनिक तौर पर उपलब्ध अनुमति वाली सूची का इस्तेमाल करता है. क्रेडेंशियल देने वाली कंपनी के तौर पर, इस सूची का इस्तेमाल किया जा सकता है. इसके अलावा, एपीआई में बताए गए JSON फ़ॉर्मैट में अपनी सूची भी दी जा सकती है. यह सेवा देने वाली कंपनी पर निर्भर करता है कि वह किस सूची का इस्तेमाल करती है. तीसरे पक्ष की क्रेडेंशियल सेवा देने वाली कंपनियों के साथ खास ऐक्सेस पाने के लिए, तीसरे पक्ष के दिए गए दस्तावेज़ देखें.

अगर ऑरिजिन फ़ील्ड खाली है, तो पुष्टि करने वाले का अनुरोध किसी Android ऐप्लिकेशन से आया है. OpenID4VP रिस्पॉन्स में शामिल किए जाने वाले ऐप्लिकेशन ऑरिजिन की गिनती android:apk-key-hash:<encoded SHA 256 fingerprint> के तौर पर की जानी चाहिए.

val appSigningInfo = request?.callingAppInfo?.signingInfoCompat?.signingCertificateHistory[0]?.toByteArray()
val md = MessageDigest.getInstance("SHA-256")
val certHash = Base64.encodeToString(md.digest(appSigningInfo), Base64.NO_WRAP or Base64.NO_PADDING)
return "android:apk-key-hash:$certHash"

होल्डर का यूज़र इंटरफ़ेस (यूआई) रेंडर करना

क्रेडेंशियल चुनने पर, होल्डर ऐप्लिकेशन चालू हो जाता है. यह उपयोगकर्ता को ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) के बारे में जानकारी देता है. इस वर्कफ़्लो को मैनेज करने के दो स्टैंडर्ड तरीके हैं:

  • अगर क्रेडेंशियल जारी करने के लिए, उपयोगकर्ता की पुष्टि करने की अतिरिक्त ज़रूरत है, तो BiometricPrompt API का इस्तेमाल करें. इसे सैंपल में दिखाया गया है.
  • इसके अलावा, कई वॉलेट साइलेंट रिटर्न का विकल्प चुनते हैं. इसके तहत, वे एक खाली गतिविधि रेंडर करते हैं, जो डेटा को तुरंत वापस कॉलिंग ऐप्लिकेशन को भेज देती है. इससे उपयोगकर्ता के क्लिक कम हो जाते हैं और उसे बेहतर अनुभव मिलता है.

क्रेडेंशियल का जवाब दिखाता है

जब आपका होल्डर ऐप्लिकेशन, नतीजे को वापस भेजने के लिए तैयार हो जाए, तो क्रेडेंशियल के जवाब के साथ गतिविधि पूरी करें:

PendingIntentHandler.setGetCredentialResponse(
    resultData,
    GetCredentialResponse(DigitalCredential(response.responseJson))
)
setResult(RESULT_OK, resultData)
finish()

अगर कोई अपवाद है, तो क्रेडेंशियल के अपवाद को इसी तरह भेजा जा सकता है:

PendingIntentHandler.setGetCredentialException(
    resultData,
    GetCredentialUnknownException() // Configure the proper exception
)
setResult(RESULT_OK, resultData)
finish()

कॉन्टेक्स्ट में क्रेडेंशियल रिस्पॉन्स वापस पाने का पूरा उदाहरण देखने के लिए, सैंपल ऐप्लिकेशन देखें.