Weryfikacja numerów telefonów za pomocą dokumentów cyfrowych

W tym przewodniku znajdziesz szczegółowe informacje o tym, jak za pomocą interfejsu DigitalCredential API uzyskiwać zweryfikowane numery telefonów użytkowników. Proces ten obejmuje 2 etapy:

  1. Wysyłanie prośby o TS.43 token: aplikacja kliencka („weryfikator”) wysyła do urządzenia użytkownika prośbę o tymczasowy token TS.43. TS.43 token to dane logowania wydane przez operatora, które reprezentują tożsamość użytkownika.
  2. Wymiana tokena na numer telefonu: backend aplikacji wymienia token TS.43 token z agregatorem lub operatorem na zweryfikowany numer telefonu użytkownika.

Wymagania wstępne

Aby wdrożyć weryfikację numeru telefonu za pomocą interfejsu DigitalCredential API, musisz mieć konto u agregatora. Agregator wchodzi w interakcje z przewoźnikami i udostępnia interfejs API wymagany przez Twoją aplikację, zwykle jako płatny punkt końcowy interfejsu API w chmurze.

Musisz też dodać te zależności do skryptu kompilacji Gradle:

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.6.0-alpha05")
    implementation("androidx.credentials:credentials-play-services-auth:1.6.0-alpha05")
}

Odlotowe

dependencies {
    implementation "androidx.credentials:credentials:1.6.0-alpha05"
    implementation "androidx.credentials:credentials-play-services-auth:1.6.0-alpha05"
}

Implementacja

Proces kompleksowy zwykle obejmuje te kroki:

  1. Wysyłanie do agregatora żądania parametrów DCQL (Digital Credential Query Language): wywołaj co najmniej 1 agregator i poproś o zestaw parametrów DCQL. DCQL umożliwia określenie dokładnych cyfrowych poświadczeń, których potrzebujesz od każdego agregatora.
  2. Utwórz żądanie OpenID4VP: w backendzie aplikacji utwórz żądanie OpenID4VP, uwzględniając parametry DCQL z agregatora. Następnie wyślij żądanie OpenID4VP do aplikacji klienta.

  3. Wywołaj interfejs Credential Manager API: w aplikacji klienckiej użyj interfejsu Credential Manager API, aby wysłać żądanie OpenID4VP do systemu operacyjnego. W odpowiedzi otrzymasz obiekt odpowiedzi OpenID4VP zawierający TS.43 Digital Credential. Te dane logowania są zaszyfrowane i może je odszyfrować tylko powiązany agregator. Po otrzymaniu tokena przewoźnika wyślij odpowiedź z aplikacji klienckiej do backendu aplikacji.

  4. Zweryfikuj odpowiedź: w backendzie aplikacji zweryfikuj odpowiedź OpenID4VP.

  5. Wymiana na numer telefonu: z backendu aplikacji wyślij do agregatora wartość TS.43 Digital Credential. Agregator weryfikuje dane logowania i zwraca zweryfikowany numer telefonu.

Ilustracja przedstawiająca proces wysyłania prośby o weryfikację numeru telefonu
Ilustracja 1. Cykl życia prośby o potwierdzenie numeru telefonu, od momentu, gdy backend weryfikatora wysyła do agregatora prośbę o parametry, do momentu, gdy zwracany jest potwierdzony numer telefonu.

Wysyłanie do pośrednika żądania parametrów DCQL

Z backendu aplikacji wyślij do agregatora żądanie obiektu poświadczeń w języku zapytań dotyczących poświadczeń cyfrowych (DCQL). W żądaniu podaj wartość jednorazową i identyfikator żądania. Agregator zwraca obiekt danych logowania DCQL o strukturze podobnej do tej:

{
  // 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"]
    }
  ]
}

Tworzenie żądania OpenID4VP

Najpierw w backendzie aplikacji utwórz obiekt dcql_query, umieszczając obiekt DCQL credential w tablicy credentials zagnieżdżonej w obiekcie dcql_query, jak pokazano w tym przykładzie:

"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"]
        }
      ]
  ]
}

Następnie utwórz żądanie OpenID4VP o tej strukturze:

{
  "protocol": "openid4vp-v1-unsigned",
  "data": {
    "response_type": "vp_token",
    "response_mode": "dc_api",
    "nonce": "...",
    "dcql_query": { ... }
  }
}
  • protocol: w przypadku próśb o weryfikację numeru telefonu musi być ustawiony na openid4vp-v1-unsigned.
  • response_typeresponse_mode: stałe oznaczające format żądania o stałych wartościach vp_tokendc_api.
  • nonce: unikalna wartość generowana przez backend dla każdego żądania. Wartość nonce w obiekcie danych logowania DCQL agregatora musi być zgodna z tą wartością nonce.
  • dcql_query: w tym przypadku użyj parametru dcql_query, aby określić, że żądany jest TS.43 Digital Credential. Możesz też poprosić o inne dokumenty cyfrowe.

Następnie umieść żądanie OpenID4VP w obiekcie żądania interfejsu DigitalCredential API i wyślij je do aplikacji klienckiej.

{
  "requests":
    [
      {
        "protocol": "openid4vp-v1-unsigned",
        "data": {
          "response_type": "vp_token",
          "response_mode": "dc_api",
          "nonce": "...",
          "dcql_query": { ... }
        }
      }
    ]
}

Ten fragment kodu pokazuje, jak wygenerować żądanie interfejsu 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

Wywoływanie interfejsu Credential Manager API

W aplikacji klienckiej wywołaj interfejs Credential Manager API, podając żądanie DigitalCredential API dostarczone przez backend aplikacji.

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)
  }
}

Odpowiedź DigitalCredential API zawiera odpowiedź OpenID4VP. Typowy plik JSON z informacjami o uwierzytelnianiu z wyniku DigitalCredential wygląda tak:

{
  "protocol": "openid4vp-v1-unsigned",

  "data": {
    "vp_token": {
      "aggregator1": ["eyJhbGciOiAiRVMy..."] # The encrypted TS.43 Digital
                                             # Credential in an array structure.
    }
  }
}

Z aplikacji klienckiej wyślij odpowiedź interfejsu DigitalCredential API z powrotem na serwer backendu, gdzie można ją zweryfikować i użyć do wymiany na zweryfikowany numer telefonu u agregatora.

Weryfikowanie odpowiedzi dotyczącej dokumentu cyfrowego

Poniżej znajdziesz przykład analizowania odpowiedzi i przeprowadzania weryfikacji w backendzie aplikacji:

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.

Wymiana na numer telefonu

Z backendu aplikacji wyślij zweryfikowany TS.43 Digital Credential do punktu końcowego agregatora, aby zweryfikować dane logowania i otrzymać zweryfikowany numer telefonu.

def processDigitalCredentialsResponse(response):
  # ... prior steps

  # Step 3: Call aggregator endpoint to exchange the verified phone number
  callAggregatorPnvEndpoint(ts43_digital_credential)