Valider des numéros de téléphone avec des certifications numériques

Ce guide explique en détail comment utiliser l'API DigitalCredential pour obtenir les numéros de téléphone validés de vos utilisateurs. Ce processus comprend deux étapes :

  1. Demander un TS.43 token : votre application cliente (le "validateur") demande un jeton TS.43 temporaire à l'appareil de l'utilisateur. TS.43 token est un identifiant émis par l'opérateur qui représente l'identité de l'utilisateur.
  2. Échangez le jeton contre un numéro de téléphone : le backend de votre application échange le TS.43 token avec un agrégateur ou un opérateur pour obtenir le numéro de téléphone validé de l'utilisateur.

Prérequis

Pour implémenter la validation du numéro de téléphone avec l'API DigitalCredential, vous avez besoin d'un compte auprès d'un agrégateur. Un agrégateur interagit avec les transporteurs et fournit la surface d'API nécessaire à votre application, généralement sous la forme d'un point de terminaison d'API Cloud facturable.

Vous devez également ajouter les dépendances suivantes à votre script de compilation Gradle :

Kotlin

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

Groovy

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

Implémentation

Le processus de bout en bout comprend généralement les étapes suivantes :

  1. Demander des paramètres DCQL (Digital Credential Query Language) à un agrégateur : appeler un ou plusieurs agrégateurs et demander un ensemble de paramètres DCQL. DCQL vous permet de spécifier les identifiants numériques exacts dont vous avez besoin pour chaque agrégateur.
  2. Créez la requête OpenID4VP : à partir du backend de votre application, créez la requête OpenID4VP en incluant les paramètres DCQL de l'agrégateur. Envoyez ensuite la requête OpenID4VP à votre application cliente.

  3. Appelez l'API Credential Manager : dans votre application cliente, utilisez l'API Credential Manager pour envoyer la requête OpenID4VP au système d'exploitation. En réponse, vous recevez un objet de réponse OpenID4VP contenant le TS.43 Digital Credential. Cet identifiant est chiffré et ne peut être déchiffré que par l'agrégateur associé. Après avoir reçu le jeton du transporteur, envoyez la réponse de votre application cliente au backend de l'application.

  4. Validez la réponse : dans le backend de votre application, validez la réponse OpenID4VP.

  5. Échange contre un numéro de téléphone : depuis le backend de votre application, envoyez le TS.43 Digital Credential à l'agrégateur. L'agrégateur valide l'identifiant et renvoie le numéro de téléphone validé.

Image montrant le flux d'une demande de validation d'un numéro de téléphone
Figure 1 : Cycle de vie d'une demande de validation d'un numéro de téléphone, depuis la demande de paramètres du backend du validateur à un agrégateur jusqu'à la réception d'un numéro de téléphone validé.

Demander des paramètres DCQL à un agrégateur

À partir du backend de votre application, envoyez une requête à l'agrégateur pour obtenir un objet d'identifiant Digital Credential Query Language (DCQL). Veillez à fournir un nonce et un ID de requête dans votre demande. L'agrégateur renvoie l'objet d'identifiant DCQL, dont la structure est semblable à la suivante :

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

Créer la requête OpenID4VP

Tout d'abord, à partir du backend de votre application, créez un objet dcql_query en plaçant l'objet d'identifiant DCQL dans un tableau credentials imbriqué dans un objet dcql_query, comme indiqué dans l'exemple suivant :

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

Créez ensuite une requête OpenID4VP avec la structure suivante :

{
  "protocol": "openid4vp-v1-unsigned",
  "data": {
    "response_type": "vp_token",
    "response_mode": "dc_api",
    "nonce": "...",
    "dcql_query": { ... }
  }
}
  • protocol : doit être défini sur openid4vp-v1-unsigned pour les demandes de validation du numéro de téléphone.
  • response_type et response_mode : constantes indiquant le format de la requête avec les valeurs fixes vp_token et dc_api, respectivement.
  • nonce : valeur unique générée par votre backend pour chaque requête. Le nonce dans l'objet d'identifiant DCQL de l'agrégateur doit correspondre à ce nonce.
  • dcql_query : dans ce cas, utilisez dcql_query pour spécifier qu'un TS.43 Digital Credential est demandé. Vous pouvez également demander d'autres identifiants numériques ici.

Ensuite, enveloppez la requête OpenID4VP dans un objet de requête de l'API DigitalCredential et envoyez-le à l'application cliente.

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

L'extrait suivant montre comment générer la requête de l'API DigitalCredential :

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

Appeler l'API Credential Manager

Dans votre application cliente, appelez l'API Credential Manager avec la requête DigitalCredential fournie par le backend de votre application.

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

La réponse de l'API DigitalCredential contient la réponse OpenID4VP. Voici un exemple de fichier JSON d'identifiants typique issu du résultat DigitalCredential :

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

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

Depuis votre application cliente, renvoyez la réponse de l'API DigitalCredential au serveur backend, où elle pourra être validée et utilisée pour échanger le numéro de téléphone validé avec un agrégateur.

Valider la réponse des identifiants numériques

Voici un exemple de la façon d'analyser la réponse et d'effectuer l'étape de validation dans le backend de votre application :

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.

Échange de numéro de téléphone

À partir du backend de votre application, envoyez le TS.43 Digital Credential validé au point de terminaison de l'agrégateur pour valider l'identifiant et recevoir le numéro de téléphone validé.

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

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