La verificación de credenciales digitales en las apps para Android se puede usar para autenticar y autorizar la identidad de un usuario (como un documento de identidad emitido por el Gobierno), propiedades sobre ese usuario (como una licencia de conducir, un título académico o atributos como la edad o la dirección) o en otras situaciones en las que se deba emitir y verificar una credencial para confirmar la autenticidad de una entidad.
La API de Verifier es compatible con Android 9 (nivel de API 28) y versiones posteriores.
Implementación
Para verificar las credenciales digitales en tu proyecto de Android, haz lo siguiente:
- Agrega dependencias a la secuencia de comandos de compilación de tu app y, luego, inicializa una clase
CredentialManager. - Crea una solicitud de credencial digital y úsala para inicializar un objeto
DigitalCredentialOptiony, luego, compila el objetoGetCredentialRequest. - Inicia el flujo de
getCredentialcon la solicitud construida para recibir unGetCredentialResponsecorrecto o controlar las excepciones que puedan ocurrir. Una vez que se recupere correctamente, valida la respuesta.
Agrega dependencias y, luego, inicializa
Agrega las siguientes dependencias a tu secuencia de comandos de compilación de Gradle:
dependencies {
implementation("androidx.credentials:credentials:1.6.0-beta01")
implementation("androidx.credentials:credentials-play-services-auth:1.6.0-beta01")
}
A continuación, inicializa una instancia de la clase CredentialManager.
val credentialManager = CredentialManager.create(context)
Crea una solicitud de credencial digital
Crea una solicitud de credencial digital y úsala para inicializar un objeto
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)
)
En el siguiente ejemplo, se muestra una solicitud de OpenId4Vp1. Para obtener detalles sobre los campos de esta solicitud, consulta la documentación de 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"
]
}
]
}
]
}
}
}
]
}
Obtén la credencial
Inicia el flujo de getCredential con la solicitud construida. Recibirás
un GetCredentialResponse correcto o un GetCredentialException si
la solicitud falla.
El flujo getCredential activa los diálogos del sistema Android para presentar las opciones de credenciales disponibles del usuario y recopilar su selección. A continuación, la app de billetera
que contiene la opción de credencial elegida mostrará las IU para recopilar el consentimiento
y realizar las acciones necesarias para generar una respuesta de credencial digital.
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}")
}
}
Solicitudes flexibles de varias credenciales
La API de Digital Credentials también admite la solicitud de varios tipos de credenciales a la vez con OpenID4VP:
- Solicitudes simultáneas: Solicita varias credenciales en una sola transacción del usuario. Por ejemplo, una app de viajes puede solicitar una tarjeta de embarque y un documento de identidad emitido por el Gobierno de forma simultánea, lo que permite que el usuario revise y otorgue su consentimiento para ambos con un solo toque.
- Cumplimiento flexible: Acepta cualquiera de los distintos tipos de credenciales o emisores. Por ejemplo, un flujo de verificación de edad puede aceptar una licencia de conducir o un pasaporte, lo que permite que los usuarios completen la solicitud con la credencial que tengan almacenada en su billetera.
Este es un ejemplo de cómo solicitar varias credenciales en una sola solicitud:
{
"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"
]
}
]
}
]
}
Cómo controlar la respuesta
Después de realizar la solicitud de credenciales, controla el GetCredentialResponse que se muestra desde 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}")
}
}
}
Controla excepciones
Tu app debería controlar los errores que se pueden generar, incluso si no hay credenciales en el dispositivo o si el usuario cancela la operación:
// 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}")
}
}