Richiedi una credenziale digitale

La verifica delle credenziali digitali all'interno delle app per Android può essere utilizzata per autenticare e autorizzare l'identità di un utente (ad esempio un documento di identità ufficiale), le proprietà relative a quell'utente (ad esempio una patente di guida, un titolo di studio o attributi come l'età o l'indirizzo) o altri scenari in cui è necessario emettere e verificare una credenziale per confermare l'autenticità di un'entità.

L'API Verifier è supportata su Android 9 (livello API 28) e versioni successive.

Implementazione

Per verificare le credenziali digitali nel tuo progetto Android, segui questi passaggi:

  1. Aggiungi le dipendenze allo script di build dell'app e inizializza una classe CredentialManager.
  2. Crea una richiesta di credenziali digitali e utilizzala per inizializzare un DigitalCredentialOption, quindi crea il GetCredentialRequest.
  3. Avvia il flusso getCredential con la richiesta creata per ricevere un GetCredentialResponse riuscito o gestire eventuali eccezioni che potrebbero verificarsi. Una volta recuperata, convalida la risposta.

Aggiungi dipendenze e inizializza

Aggiungi le seguenti dipendenze allo script di build Gradle:

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

Successivamente, inizializza un'istanza della classe CredentialManager.

val credentialManager = CredentialManager.create(context)

Crea una richiesta di credenziali digitali

Crea una richiesta di credenziali digitali e utilizzala per inizializzare un DigitalCredentialOption.

// The request in the JSON format to conform with
// the JSON-ified Credential Manager - Verifier 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)
)

L'esempio seguente mostra una richiesta OpenId4Vp1. Per informazioni dettagliate sui campi di questa richiesta, consulta la documentazione di OpenID.

{
  "requests": [
    {
      "protocol": "openid4vp-v1-unsigned",
      "data": {
        "response_type": "vp_token",
        "response_mode": "dc_api",
        "nonce": "OD8eP8BYfr0zyhgq4QCVEGN3m7C1Ht_No9H5fG5KJFk",
        "dcql_query": {
          "credentials": [
            {
              "id": "cred1",
              "format": "mso_mdoc",
              "meta": {
                "doctype_value": "org.iso.18013.5.1.mDL"
              },
              "claims": [
                {
                  "path": [
                    "org.iso.18013.5.1",
                    "family_name"
                  ]
                },
                {
                  "path": [
                    "org.iso.18013.5.1",
                    "given_name"
                  ]
                },
                {
                  "path": [
                    "org.iso.18013.5.1",
                    "age_over_21"
                  ]
                }
              ]
            }
          ]
        }
      }
    }
  ]
}

Ottieni la qualifica

Avvia il flusso getCredential con la richiesta creata. Riceverai un messaggio GetCredentialResponse in caso di esito positivo o GetCredentialException se la richiesta non va a buon fine.

Il flusso getCredential attiva le finestre di dialogo del sistema Android per presentare le opzioni di credenziali disponibili per l'utente e raccogliere la sua selezione. Successivamente, l'app wallet che contiene l'opzione di credenziale scelta mostrerà le UI per raccogliere il consenso ed eseguire le azioni richieste per generare una risposta con credenziali digitali.

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.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java}")
    }
}
Immagine che mostra il selettore delle credenziali digitali visualizzato quando viene chiamata la funzione getCredential.
Figura 1. Il selettore delle credenziali digitali visualizzato quando viene chiamato getCredential.

Richieste flessibili di più credenziali

L'API Digital Credentials supporta anche la richiesta di più tipi di credenziali contemporaneamente utilizzando OpenID4VP:

  • Richieste simultanee: richiedi più credenziali in un'unica transazione utente. Ad esempio, un'app di viaggi può richiedere contemporaneamente una carta d'imbarco e un documento di identità ufficiale, consentendo all'utente di esaminarli e acconsentire a entrambi con un solo tocco.
  • Flessibilità di evasione: accetta uno qualsiasi dei diversi tipi di credenziali o emittenti. Ad esempio, un flusso di verifica dell'età può accettare una patente di guida o un passaporto, consentendo agli utenti di soddisfare la richiesta utilizzando le credenziali memorizzate nel proprio holder.

Ecco un esempio di richiesta di più credenziali in un'unica richiesta:

{
  "credentials": [
    {
      "id": "gov_id1",
      "format": "mso_mdoc",
      "meta": {
        "doctype_value": "org.iso.18013.5.1.mDL"
      },
      "claims": [
        {
          "path": [
            "org.iso.18013.5.1",
            "age_over_21"
          ]
        }
      ]
    },
    {
      "id": "boarding_pass1",
      "format": "dc+sd-jwt",
      "meta": {
        "vct_values": [
          "https://credentials.example.airline/boarding-pass"
        ]
      },
      "claims": [
        {
          "path": [
            "flight_number"
          ]
        },
        {
          "path": [
            "seat"
          ]
        }
      ]
    }
  ]
}
Immagine che mostra il selettore delle credenziali digitali visualizzato quando vengono chiamati più tipi di credenziali.
Figura 1. Il selettore delle credenziali digitali visualizzato quando vengono chiamati più tipi di credenziali.

Gestisci la risposta

Dopo aver effettuato la richiesta di credenziali, gestisci l'oggetto GetCredentialResponse restituito da CredentialManager.

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

Gestisci le eccezioni

La tua app deve gestire gli errori che possono essere generati, anche se non sono presenti credenziali sul dispositivo o se l'utente annulla l'operazione:

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