במדריך הזה מוסבר איך להשתמש ב-DigitalCredential API כדי לקבל מספרי טלפון מאומתים של המשתמשים. התהליך כולל שני שלבים:
- שליחת בקשה ל-
TS.43 token: אפליקציית הלקוח (המאמתת) שולחת בקשה לאסימון זמני של TS.43 מהמכשיר של המשתמש. TS.43 tokenהוא פרט כניסה שהונפק על ידי הספק ומייצג את זהות המשתמש. - החלפת הטוקן במספר טלפון: הקצה העורפי של האפליקציה מחליף את הטוקן
TS.43 tokenעם צד שלישי או עם ספק סלולר כדי לקבל את מספר הטלפון המאומת של המשתמש.
תאימות לגרסת Android
ממשק ה-API לאימות מספר הטלפון נתמך ב-Android 10 (רמת API 29) ובגרסאות מתקדמות יותר.
דרישות מוקדמות
כדי להטמיע אימות מספר טלפון באמצעות DigitalCredential API, צריך חשבון אצל ספק שירותי צד שלישי. מצטבר מבצע אינטראקציה עם ספקים ומספק את ממשק ה-API הנדרש לאפליקציה שלכם, בדרך כלל כנקודת קצה של API בענן שניתן לחיוב.
צריך גם להוסיף את יחסי התלות הבאים לסקריפט ה-build של Gradle:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.6.0-rc02") implementation("androidx.credentials:credentials-play-services-auth:1.6.0-rc02") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.6.0-rc02" implementation "androidx.credentials:credentials-play-services-auth:1.6.0-rc02" }
הטמעה
בדרך כלל התהליך המלא כולל את השלבים הבאים:
- בקשת פרמטרים של DCQL (שפת שאילתות של מסמכים דיגיטליים) מאגרגטור: מתקשרים לאגרגטור אחד או יותר ומבקשים קבוצה של פרמטרים של DCQL. בעזרת DCQL אפשר לציין את פרטי הכניסה הדיגיטליים המדויקים שאתם צריכים מכל צובר.
יוצרים את בקשת OpenID4VP: בבקשות OpenID4VP שיוצרים בבק-אנד של האפליקציה, כוללים את הפרמטרים של DCQL מהאגרגטור. לאחר מכן, שולחים את בקשת OpenID4VP לאפליקציית הלקוח.
הפעלת Credential Manager API: באפליקציית הלקוח, משתמשים ב-Credential Manager API כדי לשלוח את בקשת OpenID4VP למערכת ההפעלה. בתגובה, מקבלים אובייקט תגובה של OpenID4VP שמכיל את
TS.43 Digital Credential. פרטי הכניסה האלה מוצפנים, ורק המצטבר המשויך יכול לפענח אותם. אחרי שמקבלים את האסימון של חברת התובלה, שולחים את התגובה מאפליקציית הלקוח אל ה-Backend של האפליקציה.אימות התגובה: בשרת העורפי של האפליקציה, מאמתים את התגובה של OpenID4VP.
החלפה במספר טלפון: מהקצה העורפי של האפליקציה, שולחים את
TS.43 Digital Credentialלמרכז האגרגציה. הספק המצטבר מאמת את פרטי הכניסה ומחזיר את מספר הטלפון המאומת.
בקשת פרמטרים של DCQL מאגרגטור
משרת הקצה העורפי של האפליקציה, שולחים בקשה למצטבר לאובייקט של אישורים בשפת שאילתות של אישורים דיגיטליים (DCQL). חשוב לספק בבקשה ערך חד-פעמי ומזהה בקשה. האגרגטור מחזיר את אובייקט פרטי הכניסה של DCQL, עם מבנה שדומה לזה:
{
// The credential ID is mapped to the request ID that is sent in your request to the aggregator.
"id": "aggregator1",
"format": "dc-authorization+sd-jwt",
"meta": {
"vct_values": [
"number-verification/device-phone-number/ts43"
],
"credential_authorization_jwt": "..."
},
"claims": [
{
"path": ["subscription_hint"],
"values": [1]
},
{
"path": ["phone_number_hint"],
"values": ["+14155552671"]
}
]
}
יצירת בקשת OpenID4VP
קודם כל, יוצרים אובייקט dcql_query מהקצה העורפי של האפליקציה, על ידי הצבת אובייקט האישורים של DCQL במערך credentials שמוטמע באובייקט dcql_query, כמו בדוגמה הבאה:
"dcql_query": {
"credentials": [
"id": "aggregator1",
"format": "dc-authorization+sd-jwt",
"meta": {
"vct_values": [
"number-verification/device-phone-number/ts43"
],
"credential_authorization_jwt": "..."
},
"claims": [
{
"path": ["subscription_hint"],
"values": [1]
},
{
"path": ["phone_number_hint"],
"values": ["+14155552671"]
}
]
]
}
לאחר מכן, יוצרים בקשת OpenID4VP עם המבנה הבא:
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "...",
"dcql_query": { ... }
}
}
-
protocol: צריך להגדיר את הערךopenid4vp-v1-unsignedלבקשות לאימות מספר טלפון. -
response_typeו-response_mode: קבועים שמציינים את הפורמט של הבקשה עם הערכים הקבועיםvp_tokenו-dc_api, בהתאמה. -
nonce: ערך ייחודי שנוצר על ידי ה-Backend לכל בקשה. ה-nonce באובייקט של פרטי הכניסה של המצטבר ב-DCQL צריך להיות זהה ל-nonce הזה. -
dcql_query: במקרה הזה, משתמשים ב-dcql_queryכדי לציין שמבוקשTS.43 Digital Credential. אפשר גם לבקש כאן אישורים דיגיטליים אחרים.
לאחר מכן, עוטפים את בקשת OpenID4VP באובייקט בקשת DigitalCredential API ושולחים אותו לאפליקציית הלקוח.
{
"requests":
[
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "...",
"dcql_query": { ... }
}
}
]
}
בקטע הקוד הבא אפשר לראות איך יוצרים את הבקשה ל-DigitalCredential API:
def GenerateDCRequest():
credentials = []
aggregator1_dcql = call_aggregator_endpoint(nonce, "aggregator1", additional_params)
credentials.append(aggregator1_dcql) # You can optionally work with multiple
# aggregators, or request other types of credentials
val dc_request =
{
"requests":
[
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "...",
"dcql_query": {"credentials": credentials}
}
}
]
}
return dc_request
שליחת קריאה ל-Credential Manager API
באפליקציית הלקוח, מבצעים קריאה ל-Credential Manager API, עם בקשת DigitalCredential API שסופקה על ידי הקצה העורפי של האפליקציה.
val requestJson = generateTs43DigitalCredentialRequestFromServer()
val digiCredOption = GetDigitalCredentialOption(requestJson = requestJson)
val getCredRequest = GetCredentialRequest(
listOf(digiCredOption)
)
coroutineScope.launch {
try {
val response = credentialManager.getCredential(
context = activityContext,
request = getCredRequest
)
val credential = response.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}")
}
}
} catch (e : GetCredentialException) {
// If user cancels the operation, the feature isn't available, or the
// SIM doesn't support the feature, a GetCredentialCancellationException
// will be returned. Otherwise, a GetCredentialUnsupportedException will
// be returned with details in the exception message.
handleFailure(e)
}
}
התגובה של DigitalCredential API מכילה את התגובה של OpenID4VP. דוגמה ל-JSON של פרטי כניסה מתוצאת DigitalCredential:
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"vp_token": {
"aggregator1": ["eyJhbGciOiAiRVMy..."] # The encrypted TS.43 Digital
# Credential in an array structure.
}
}
}
מאפליקציית הלקוח, שולחים את התגובה של DigitalCredential API בחזרה לשרת הבק-אנד, שם אפשר לאמת אותה ולהשתמש בה כדי להחליף אותה במספר הטלפון המאומת באמצעות צד שלישי.
אימות התשובה של פרטי הכניסה הדיגיטליים
הדוגמה הבאה מראה איך לנתח את התגובה ולבצע את שלב האימות בבק-אנד של האפליקציה:
def processDigitalCredentialsResponse(response):
# Step 1: Parse out the TS.43 Digital Credential from the response
openId4VpResponse = response['data']
ts43_digital_credential = response['vp_token']["aggregator1"][0]
# Step 2: Perform response validation
verifyResponse(ts43_digital_credential)
def verifyResponse(ts43_digital_credential):
# The returned ts43_digital_credential is an SD-JWT-based Verifiable Credentials
# (SD-JWT VC) as defined in this IETF spec. The section 3.4 of the specification
# outlines how to validate the credential. At a high level, the steps involves
# validating (1) the nonce in the response credential matches the one in the
# request, (2) the integrity of the credential by checking the credential is
# signed by the trusted issuer Android Telephony, and (3) other validity
# properties associated with this credential, such as issue time and expiration
# time
# In most cases, you can use an SD-JWT VC library to perform these validations.
# Some aggregators may also perform the validation logic for you. Check with your
# aggregator to decide the exact scope of the validation required.
החלפה של מספר טלפון
משרת הקצה של האפליקציה, שולחים את TS.43 Digital Credential המאומת לנקודת הקצה של המצטבר כדי לאמת את פרטי הכניסה ולקבל את מספר הטלפון המאומת.
def processDigitalCredentialsResponse(response):
# ... prior steps
# Step 3: Call aggregator endpoint to exchange the verified phone number
callAggregatorPnvEndpoint(ts43_digital_credential)