Os IDs digitais podem ser aceitos em fluxos no app e na Web. Para aceitar credenciais da Carteira do Google, você precisa fazer o seguinte:
- Integre usando o app ou a Web seguindo as instruções fornecidas e
- Preencha este formulário para solicitar e concordar com os Termos de Serviço de aceitação de credenciais da Carteira do Google.
Pré-requisitos
Para testar a apresentação de documentos de identificação de forma digital, primeiro você precisa se inscrever no programa Beta público usando a conta de teste pretendida (que precisa ser uma conta do Gmail). Em seguida, forneça os detalhes ao seu contato do Google designado.
- Link dos Termos de Serviço
- Logotipo
- Site
- IDs de pacotes de apps (para integrações de apps Android)
- Como incluir builds de desenvolvimento / depuração
- Assinatura do app
$ $ANDROID_SDK/build-tools/$BUILD_TOOLS_VERSION/apksigner verify --print-certs -v $APK
- ID do Gmail usado para participar da versão Beta pública
Formatos de credencial aceitos
Existem vários padrões propostos que definem o formato de dados de documentos de identidade digital, sendo que dois deles têm grande aceitação no setor:
- mdocs: definidos pela ISO.
- Credenciais verificáveis do w3c: definidas pelo w3c.
Embora o Gerenciador de credenciais do Android ofereça suporte aos dois formatos, a Carteira do Google só aceita documentos digitais baseados em mdoc no momento.
Credenciais compatíveis
A Carteira do Google oferece suporte a dois tipos de credenciais:
- Carteira de Habilitação para Dispositivos Móveis (mDL)
- Documento de identificação
É possível solicitar qualquer credencial no fluxo com uma única mudança de parâmetro.
Experiência do usuário
Quando um aplicativo solicita atributos de identidade, o seguinte processo ocorre:
Identificação de credenciais:o aplicativo consulta as carteiras disponíveis para identificar as credenciais que podem atender à solicitação. Em seguida, o Android apresenta um seletor da interface do sistema, mostrando as informações a serem compartilhadas. Isso permite que o usuário tome uma decisão informada sobre qual credencial usar.
Seleção do usuário e interação com a carteira:o usuário seleciona uma credencial e o Android invoca o app de carteira correspondente para concluir a transação. O app da carteira pode apresentar a própria tela de consentimento ou exigir a confirmação biométrica.
Resultado:se o usuário consentir, as credenciais de identidade selecionadas serão compartilhadas com o aplicativo solicitante. Se o usuário recusar, um erro será retornado.
Formato da solicitação de credenciais de identificação da carteira
Confira um exemplo de uma solicitação requestJson
de mdoc para receber credenciais de identidade
de qualquer carteira em um dispositivo Android ou na Web.
{
"providers": [{
"protocol": "openid4vp",
"request": "<credential_request>"
}]
}
Solicitar criptografia
O client_metadata
contém a chave pública de criptografia para cada solicitação.
Você vai precisar armazenar chaves privadas para cada solicitação e usá-las para autenticar
e autorizar o token recebido do app de carteira.
O parâmetro credential_request
em requestJson
consiste nos seguintes
campos.
{
"response_type": "vp_token",
"response_mode": "dc_api.jwt",
"nonce": "1234",
"origin": "https://www.website.com", // omit this parameter for app
"dcql_query": {
"credentials": [
{
"id": "cred1",
"format": "mso_mdoc",
"meta": {
"doctype_value": "org.iso.18013.5.1.mDL" // this is for mDL. Use com.google.wallet.idcard.1 for ID pass
},
"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_18"
]
}
]
}
]
},
"client_metadata": {
"jwks": {
"keys": [ // sample request encryption key
{
"kty": "EC",
"crv": "P-256",
"x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
"y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
"use": "enc",
"kid" : "1",
"alg" : "ECDH-ES",
}
]
},
"authorization_encrypted_response_alg": "ECDH-ES",
"authorization_encrypted_response_enc": "A128GCM"
}
}
É possível solicitar qualquer número de atributos compatíveis de qualquer credencial de identidade armazenada na Carteira do Google.
No app
Para solicitar credenciais de identidade nos seus apps Android, siga estas etapas:
Atualizar dependências
No build.gradle do projeto, atualize as dependências para usar o Gerenciador de credenciais (Beta):
dependencies {
implementation("androidx.credentials:credentials:1.5.0-beta01")
// optional - needed for credentials support from play services, for devices running Android 13 and below.
implementation("androidx.credentials:credentials-play-services-auth:1.5.0-beta01")
}
Configurar o Gerenciador de credenciais
Para configurar e inicializar um objeto CredentialManager
, adicione uma lógica semelhante
a esta:
// Use your app or activity context to instantiate a client instance of CredentialManager.
val credentialManager = CredentialManager.create(context)
Solicitar atributos de identidade
Em vez de especificar parâmetros individuais para solicitações de identidade, o app os fornece todos juntos como uma string JSON na CredentialOption. O Gerenciador de credenciais transmite essa string JSON para as carteiras digitais disponíveis sem examinar o conteúdo delas. Cada carteira é responsável por: - Analisar a string JSON para entender a solicitação de identidade. - Determinar quais das credenciais armazenadas, se houver, atendem à solicitação.
Recomendamos que os parceiros criem as solicitações no servidor, mesmo para integrações de apps Android.
Você vai usar o requestJson
do formato de solicitação
que consiste no request
na chamada de função GetDigitalCredentialOption()
// The request in the JSON format to conform with
// the JSON-ified Digital Credentials 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)
)
coroutineScope.launch {
try {
val result = credentialManager.getCredential(
context = activityContext,
request = getCredRequest
)
verifyResult(result)
} catch (e : GetCredentialException) {
handleFailure(e)
}
}
Verificar e validar a resposta
Depois de receber uma resposta da carteira, verifique se ela
é bem-sucedida e contém a resposta credentialJson
.
// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
val credential = result.credential
when (credential) {
is DigitalCredential -> {
val responseJson = credential.credentialJson
validateResponseOnServer(responseJson) // make a server call to validate the response
}
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}")
}
}
A resposta credentialJson
contém um identityToken (JWT) criptografado,
definido pelo W3C. O app Carteira é responsável por criar essa resposta.
Exemplo:
"response" : {
<encrpted_response>
}
Você vai transmitir essa resposta de volta ao servidor para validar a autenticidade dela. Confira as etapas para validar a resposta da credencial.
Web
Para solicitar credenciais de identidade usando a API Digital Credentials no Chrome, você precisa se inscrever no teste de origem da API Digital Credentials.
const credentialResponse = await navigator.credentials.get({
digital: {
providers: [{
protocol: "openid4vp",
request: "<credential_request>"
}]
},
})
Enviar a resposta desta API de volta ao servidor para validar a resposta de credencial
Etapas para validar a resposta de credencial
Ao receber o identityToken criptografado do seu app ou site, é necessário realizar várias validações antes de confiar na resposta.
Descriptografar a resposta usando a chave privada
A primeira etapa é descriptografar o token usando a chave privada salva e receber uma resposta JSON.
Exemplo:
TinkConfig.register(); // Sample Private Key JWK String privateKeysetJson = '{"crv":"P-256","d":"evjMOTTqWeTKKOrtWxq9kO_a5rHW_ja_wrT6eH7VPzs","kty":"EC","x":"C2Ka4HcNelUIxMjscNRq1GjFamP-fskGjvR6aY9Ac_Q","y":"a1tXuHhBnsGaaFyNzpqADY_Cp39Q56L2VLuADRsWncE"}'; // Read the private keyset for Hybrid Decryption KeysetHandle privateKeysetHandle = CleartextKeysetHandle.read( JsonKeysetReader.withString(privateKeysetJson)); HybridDecrypt decrypt = privateKeysetHandle.getPrimitive(HybridDecrypt.class); // Split the JWE string by the '.' delimiter String[] parts = jweString.split("\\."); if (parts.length != 5) { throw new IllegalArgumentException("Invalid JWE format (expected 5 parts)"); } // The encrypted data is typically in the second part (index 1) byte[] ciphertext = Base64.getUrlDecoder().decode(parts[1]); // Associated data (AAD) is often the third part (index 2) byte[] associatedData = Base64.getUrlDecoder().decode(parts[2]); // Decrypt the ciphertext byte[] decryptedPayloadBytes = decrypt.decrypt(ciphertext, associatedData); String decryptedJsonResponse = new String(decryptedPayloadBytes, StandardCharsets.UTF_8);
decrypted_json_response
vai resultar em um JSONvp_token
contendo a credencial{ "vp_token": { "cred1": "<credential_token>" } }
Criar a transcrição da sessão
A próxima etapa é criar o SessionTranscript da ISO/IEC 18013-5:2021 com uma estrutura de transferência específica para Android ou Web:
SessionTranscript = [ null, // DeviceEngagementBytes not available null, // EReaderKeyBytes not available [ "OID4VPDCAPIHandover", AndroidHandoverDataBytes // BrowserHandoverDataBytes for Web ] ]
Para as transferências do Android / Web, você vai precisar usar o mesmo valor de uso único que usou para gerar
credential_request
.Transferência do Android
AndroidHandoverData = [ origin, // "android:apk-key-hash:<base64SHA256_ofAppSigningCert>", clientId, // "android-origin:<app_package_name>", nonce, // nonce that was used to generate credential request ] AndroidHandoverDataBytes = hashlib.sha256(cbor2.dumps(AndroidHandoverData)).digest()
Transferência de navegador
BrowserHandoverData =[ origin, // Origin URL clientId, // "web-origin:<origin>" nonce, // nonce that was used to generate credential request ] BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
Usando o
SessionTranscript
, a DeviceResponse precisa ser validada de acordo com a cláusula 9 da ISO/IEC 18013-5:2021. Isso inclui várias etapas, como:Verificar o certificado do emissor do estado. Confira os certificados IACA do emissor com suporte.
Verificar a assinatura do MSO (18013-5, seção 9.1.2)
Calcular e verificar os resumos de valor para elementos de dados (18013-5, seção 9.1.2)
Verificar a assinatura
deviceSignature
(18013-5, seção 9.1.3)
{
"version": "1.0",
"documents": [
{
"docType": "org.iso.18013.5.1.mDL",
"issuerSigned": {
"nameSpaces": {...}, // contains data elements
"issuerAuth": [...] // COSE_Sign1 w/ issuer PK, mso + sig
},
"deviceSigned": {
"nameSpaces": 24(<< {} >>), // empty
"deviceAuth": {
"deviceSignature": [...] // COSE_Sign1 w/ device signature
}
}
}
],
"status": 0
}
Testar a solução
Para testar sua solução, crie e execute o app Android detentor da referência de código aberto. Confira abaixo as etapas para criar e executar o app detentor de referência:
- Clone o repositório dos apps de referência.
- Abra o projeto no Android Studio.
- Crie e execute o rótulo
appholder
no dispositivo ou emulador Android.