Processar a emissão de credenciais com o app da carteira

Para receber e armazenar credenciais de emissores, o app do titular precisa processar os fluxos de emissão. A emissão de credenciais pode ser acionada de duas maneiras:

  • Fluxo iniciado pelo emissor: o usuário aciona uma solicitação para emitir um VDC de um aplicativo ou site do emissor. Por exemplo, um site pode oferecer aos usuários a opção de "Adicionar seu passaporte à carteira". O emissor chama a API de emissão do Gerenciador de credenciais para fazer uma solicitação de oferta de credencial OpenID4VCI. Para processar essas solicitações, o titular precisa primeiro se integrar ao Gerenciador de credenciais para registrar os metadados. O Gerenciador de credenciais vai mostrar opções relevantes para o usuário selecionar. Depois que o usuário selecionar uma opção de titular, o app do titular será invocado e poderá prosseguir com as etapas necessárias para concluir a emissão.
  • Fluxo iniciado pelo titular: o usuário solicita a adição de um VDC pelo app do titular. Por exemplo, um titular pode oferecer um botão para "Adicionar seu passaporte". Nesse caso, o titular mantém a lista de emissores compatíveis e os metadados. Ele não precisa se integrar ao Gerenciador de credenciais do Android para concluir essa função.

Para mais informações sobre como as credenciais funcionam com a API Holder, consulte Sobre o armazenamento de credenciais digitais.

Compatibilidade com versões do Android

A API Holder pode ser usada no Android 6 (nível 23 da API) e versões mais recentes.

Implementação

Para usar a API Credential Manager Holder, adicione as seguintes dependências ao script de build do módulo do app:

Groovy

dependencies {
    // Use to implement credentials registrys

    implementation "androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-digitalcredentials-openid:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-digitalcredentials-sdjwtvc:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-provider:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04"

}

Kotlin

dependencies {
    // Use to implement credentials registrys

    implementation("androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-digitalcredentials-openid:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-digitalcredentials-sdjwtvc:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-provider:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04")

}

Criar o RegistryManager

Crie uma instância de RegistryManager e registre uma solicitação de RegisterCreationOptionsRequest com ela.

val registryManager = RegistryManager.create(context)

try {
    registryManager.registerCreationOptions(object :
        RegisterCreationOptionsRequest(
            creationOptions = buildIssuanceData(),
            matcher = loadIssuanceMatcher(),
            type = DigitalCredential.TYPE_DIGITAL_CREDENTIAL,
            id = "openid4vci",
        ) {}
    )
} catch (e: Exception) {
    Log.e(TAG, "Issuance registration failed.", e)
}

O matcher é um arquivo binário do WebAssembly (Wasm) que recebe o conjunto creationOptions durante o registro e a oferta de credencial enviada pelo emissor para determinar as entradas mostradas na interface do Gerenciador de Credenciais. Consulte o app de carteira de código aberto para ver um exemplo de correspondência.

Processar uma solicitação de emissão

Em seguida, a carteira precisa processar quando uma opção de criação de credencial é selecionada pelo usuário. Defina uma atividade que detecte o filtro de intent androidx.credentials.registry.provider.action.CREATE_CREDENTIAL, conforme demonstrado na carteira de exemplo.

A intent que inicia a atividade contém a solicitação de criação e a origem da chamada, que podem ser extraídas com a função PendingIntentHandler.retrieveProviderCreateCredentialRequest. A API retorna um ProviderCreateCredentialRequest que contém todas as informações associadas à solicitação de criação. Há dois componentes principais:

  • O app que fez a solicitação. É possível recuperar isso com getCallingAppInfo.
  • A solicitação do app de ligação. É possível recuperá-la com getCallingRequest, que retorna um CreateCredentialRequest. Se a solicitação for para credenciais digitais, ela será uma instância de CreateDigitalCredentialRequest, que contém o JSON da solicitação de emissão na propriedade requestJson. É possível processar isso com o seguinte exemplo de código:
val pendingIntentRequest =
    PendingIntentHandler.retrieveProviderCreateCredentialRequest(intent)
val request = pendingIntentRequest!!.callingRequest
if (request is CreateDigitalCredentialRequest) {
    Log.i(TAG, "Got DC creation request: ${request.requestJson}")
    processCreationRequest(request.requestJson)
}

Atestado de chaves

Observe o seguinte sobre o atestado de chave:

  • Ao gerar um atestado de chave, talvez você esteja usando BigInteger.toByteArray para converter os materiais de chave em, por exemplo, uma chave da Web JSON. Às vezes, esse método pode adicionar um byte de sinal e causar um erro de validação. Se isso acontecer, remova esses bytes antes de enviar o atestado de chave ao emissor.
  • Recomendamos usar android_key_attestation como o tipo de prova de chave.

Retornar a resposta de criação

Depois que a carteira concluir as etapas necessárias para salvar a credencial, encerre a atividade com a resposta da credencial:

val resultData = Intent()
PendingIntentHandler.setCreateCredentialResponse(
    resultData,
    CreateDigitalCredentialResponse(response.responseJson)
)
setResult(RESULT_OK, resultData)
finish()

Se houver uma exceção, você poderá enviar a exceção de credencial de maneira semelhante:

val resultData = Intent()
PendingIntentHandler.setCreateCredentialException(
    resultData,
    CreateCredentialUnknownException() // Configure the proper exception
)
setResult(RESULT_OK, resultData)
finish()

Para conferir um exemplo completo de como retornar a resposta de credencial no contexto, consulte o app de exemplo.