O Gerenciador de credenciais é uma nova API do Jetpack que oferece suporte a login múltiplo, como nome de usuário e senha, chaves de acesso e soluções de login federadas (como o Fazer login com o Google) em uma única API, simplificando a integração para desenvolvedores.
Além disso, para os usuários, o Gerenciador de credenciais unifica a interface de login em todos os métodos de autenticação, deixando o processo de login em apps mais claro e fácil, independente do método escolhido.
Nesta página, explicamos o conceito de chaves de acesso e as etapas para implementar o suporte do lado do cliente em soluções de autenticação, incluindo chaves de acesso, usando a API Credential Manager. Há também uma página de perguntas frequentes separada que responde perguntas mais detalhadas e específicas.
Seu feedback é essencial para melhorar a API Credential Manager. Compartilhe qualquer problema encontrado ou ideia para melhorar a API usando o link abaixo:
Sobre chaves de acesso
As chaves de acesso são substitutas mais simples e seguras para as senhas. Com as chaves de acesso, os usuários podem fazer login em apps e sites usando um sensor biométrico (como reconhecimento facial ou de impressão digital), um PIN ou um padrão. Assim, o usuário tem uma experiência de login simplificada, sem precisar se lembrar de nomes de usuário ou senhas definidas.
As chaves de acesso usam WebAuthn (Web Authentication), um padrão desenvolvido em parceria pela FIDO Alliance e o World Wide Web Consortium (W3C). WebAuthn usa a criptografia de chave pública para autenticar o usuário. O site ou app em que o usuário faz login pode conferir e armazenar a chave pública, mas nunca a chave privada. A chave privada fica oculta e é mantida em segurança. Por serem exclusivas e ficarem vinculadas ao site ou app, as chaves de acesso não correm risco de phishing, o que aumenta ainda mais a segurança.
O Gerenciador de credenciais permite que os usuários criem chaves de acesso e armazenem essas informações no Gerenciador de senhas do Google.
Leia Autenticação do usuário com chaves de acesso para saber como implementar fluxos de autenticação de chaves de acesso com o Gerenciador de credenciais.
Pré-requisitos
Para usar o Gerenciador de credenciais, conclua as etapas desta seção.
Usar uma versão recente da plataforma
O Gerenciador de credenciais pode ser usado no Android 4.4 (nível 19 da API) e versões mais recentes.
Adicionar dependências ao app
Adicione estas dependências ao script de build do módulo do app:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.5.0-alpha05") // 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-alpha05") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.5.0-alpha05" // 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-alpha05" }
Preservar classes no arquivo ProGuard
No arquivo proguard-rules.pro
do módulo, adicione estas diretivas:
-if class androidx.credentials.CredentialManager
-keep class androidx.credentials.playservices.** {
*;
}
Saiba mais sobre como reduzir, ofuscar e otimizar seu app.
Adicionar suporte para Digital Asset Links
Para ativar o suporte a chaves de acesso no seu app Android, associe o app a um site próprio. Para declarar essa associação, siga estas etapas:
Crie um arquivo JSON do Digital Asset Links. Por exemplo, para declarar que o site
https://signin.example.com
e um app Android com o nome de pacotecom.example
podem compartilhar credenciais de login, crie um arquivo chamadoassetlinks.json
com o seguinte conteúdo:[ { "relation" : [ "delegate_permission/common.handle_all_urls", "delegate_permission/common.get_login_creds" ], "target" : { "namespace" : "android_app", "package_name" : "com.example.android", "sha256_cert_fingerprints" : [ SHA_HEX_VALUE ] } } ]
O campo
relation
é uma matriz de uma ou mais strings que descrevem o relacionamento que está sendo declarado. Para declarar que apps e sites compartilham credenciais de login, especifique as relações comodelegate_permission/handle_all_urls
edelegate_permission/common.get_login_creds
.O campo
target
é um objeto que especifica o recurso a que a declaração se aplica. Os campos a seguir identificam um site:namespace
web
site
O URL do site, no formato
https://domain[:optional_port]
, por exemplo,https://www.example.com
.O domain precisa ser totalmente qualificado, e optional_port precisa ser omitido ao usar a porta 443 para HTTPS.
Um destino
site
só pode ser um domínio raiz. Não é possível limitar uma associação de app a um subdiretório específico. Não inclua um caminho no URL, por exemplo, uma barra.Não é esperado que os subdomínios apresentem correspondências: ou seja, se você especificar domain como
www.example.com
, o domíniowww.counter.example.com
não será associado ao app.Os campos a seguir identificam um app Android.
namespace
android_app
package_name
Nome do pacote declarado no manifesto do app. Por exemplo, com.example.android
sha256_cert_fingerprints
Impressões digitais SHA256 do certificado assinado do app. Hospede o arquivo JSON do Digital Assets Link no seguinte local no domínio de login:
https://domain[:optional_port]/.well-known/assetlinks.json
Por exemplo, se o domínio de login for
signin.example.com
, hospede o arquivo JSON emhttps://signin.example.com/.well-known/assetlinks.json
.O tipo MIME do arquivo Digital Assets Link precisa ser JSON. Verifique se o servidor envia um cabeçalho
Content-Type: application/json
na resposta.Verifique se o host permite que o Google recupere o arquivo do Digital Asset Link. Se você tiver um arquivo
robots.txt
, ele precisa permitir que o agente do Googlebot extraia/.well-known/assetlinks.json
. A maioria dos sites pode permitir que qualquer agente automatizado extraia arquivos no caminho/.well-known/
para que outros serviços possam acessar os metadados nesses arquivos:User-agent: * Allow: /.well-known/
Adicione a seguinte linha ao arquivo de manifesto em
<application>
:<meta-data android:name="asset_statements" android:resource="@string/asset_statements" />
Se você está usando o login com senha pelo Gerenciador de credenciais, siga esta etapa para configurar a vinculação de ativos digitais no manifesto. Esta etapa não será necessária se você estiver usando apenas chaves de acesso.
Declare a associação no app Android. Adicione um objeto que especifique os arquivos
assetlinks.json
a serem carregados. É necessário fazer o escape de todos os apóstrofos e aspas que você usa na string. Por exemplo:<string name="asset_statements" translatable="false"> [{ \"include\": \"https://signin.example.com/.well-known/assetlinks.json\" }] </string>
> GET /.well-known/assetlinks.json HTTP/1.1 > User-Agent: curl/7.35.0 > Host: signin.example.com < HTTP/1.1 200 OK < Content-Type: application/json
Configurar o Gerenciador de credenciais
Para configurar e inicializar um objeto CredentialManager
, adicione uma lógica parecida com
esta:
Kotlin
// Use your app or activity context to instantiate a client instance of // CredentialManager. val credentialManager = CredentialManager.create(context)
Java
// Use your app or activity context to instantiate a client instance of // CredentialManager. CredentialManager credentialManager = CredentialManager.create(context)
Indicar campos de credenciais
No Android 14 e versões mais recentes, o atributo isCredential
pode ser usado para
indicar campos de credenciais, como nome de usuário ou senha. Esse atributo
indica que essa visualização é um campo de credencial criado para funcionar com o
Gerenciador de credenciais e provedores de credenciais de terceiros, ajudando os serviços de preenchimento automático
a fornecer melhores sugestões. Quando o app usa a API Credential
Manager, a página inferior do Gerenciador de credenciais com credenciais disponíveis é
mostrada e não é necessário mostrar a caixa de diálogo do preenchimento automático para
nome de usuário ou senha. Da mesma forma, não é necessário mostrar a caixa de diálogo de
salvamento do preenchimento automático para senhas, porque o app vai solicitar a API Credential Manager
para salvar as credenciais.
Para usar o atributo isCredential
, adicione-o às visualizações relevantes:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isCredential="true"
...
/>
Fazer login do usuário
Para extrair todas as opções de chave de acesso e senha associadas à conta do usuário, siga estas etapas:
Inicialize as opções de autenticação de senha e chave de acesso:
Kotlin
// Retrieves the user's saved password for your app from their // password provider. val getPasswordOption = GetPasswordOption() // Get passkey from the user's public key credential provider. val getPublicKeyCredentialOption = GetPublicKeyCredentialOption( requestJson = requestJson )
Java
// Retrieves the user's saved password for your app from their // password provider. GetPasswordOption getPasswordOption = new GetPasswordOption(); // Get passkey from the user's public key credential provider. GetPublicKeyCredentialOption getPublicKeyCredentialOption = new GetPublicKeyCredentialOption(requestJson);
Use as opções extraídas da etapa anterior para criar a solicitação de login.
Kotlin
val getCredRequest = GetCredentialRequest( listOf(getPasswordOption, getPublicKeyCredentialOption) )
Java
GetCredentialRequest getCredRequest = new GetCredentialRequest.Builder() .addCredentialOption(getPasswordOption) .addCredentialOption(getPublicKeyCredentialOption) .build();
Inicie o fluxo de login:
Kotlin
coroutineScope.launch { try { val result = credentialManager.getCredential( // Use an activity-based context to avoid undefined system UI // launching behavior. context = activityContext, request = getCredRequest ) handleSignIn(result) } catch (e : GetCredentialException) { handleFailure(e) } } fun handleSignIn(result: GetCredentialResponse) { // Handle the successfully returned credential. val credential = result.credential when (credential) { is PublicKeyCredential -> { val responseJson = credential.authenticationResponseJson // Share responseJson i.e. a GetCredentialResponse on your server to // validate and authenticate } is PasswordCredential -> { val username = credential.id val password = credential.password // Use id and password to send to your server to validate // and authenticate } is CustomCredential -> { // If you are also using any external sign-in libraries, parse them // here with the utility functions provided. if (credential.type == ExampleCustomCredential.TYPE) { try { val ExampleCustomCredential = ExampleCustomCredential.createFrom(credential.data) // Extract the required credentials and complete the authentication as per // the federated sign in or any external sign in library flow } catch (e: ExampleCustomCredential.ExampleCustomCredentialParsingException) { // Unlikely to happen. If it does, you likely need to update the dependency // version of your external sign-in library. Log.e(TAG, "Failed to parse an ExampleCustomCredential", e) } } else { // Catch any unrecognized custom credential type here. Log.e(TAG, "Unexpected type of credential") } } else -> { // Catch any unrecognized credential type here. Log.e(TAG, "Unexpected type of credential") } } }
Java
credentialManager.getCredentialAsync( // Use activity based context to avoid undefined // system UI launching behavior activity, getCredRequest, cancellationSignal, <executor>, new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() { @Override public void onResult(GetCredentialResponse result) { handleSignIn(result); } @Override public void onError(GetCredentialException e) { handleFailure(e); } } ); public void handleSignIn(GetCredentialResponse result) { // Handle the successfully returned credential. Credential credential = result.getCredential(); if (credential instanceof PublicKeyCredential) { String responseJson = ((PublicKeyCredential) credential).getAuthenticationResponseJson(); // Share responseJson i.e. a GetCredentialResponse on your server to validate and authenticate } else if (credential instanceof PasswordCredential) { String username = ((PasswordCredential) credential).getId(); String password = ((PasswordCredential) credential).getPassword(); // Use id and password to send to your server to validate and authenticate } else if (credential instanceof CustomCredential) { if (ExampleCustomCredential.TYPE.equals(credential.getType())) { try { ExampleCustomCredential customCred = ExampleCustomCredential.createFrom(customCredential.getData()); // Extract the required credentials and complete the // authentication as per the federated sign in or any external // sign in library flow } catch (ExampleCustomCredential.ExampleCustomCredentialParsingException e) { // Unlikely to happen. If it does, you likely need to update the // dependency version of your external sign-in library. Log.e(TAG, "Failed to parse an ExampleCustomCredential", e); } } else { // Catch any unrecognized custom credential type here. Log.e(TAG, "Unexpected type of credential"); } } else { // Catch any unrecognized credential type here. Log.e(TAG, "Unexpected type of credential"); } }
O exemplo abaixo mostra como formatar a solicitação JSON ao receber uma chave de acesso:
{
"challenge": "T1xCsnxM2DNL2KdK5CLa6fMhD7OBqho6syzInk_n-Uo",
"allowCredentials": [],
"timeout": 1800000,
"userVerification": "required",
"rpId": "credential-manager-app-test.glitch.me"
}
O exemplo abaixo mostra como uma resposta JSON pode ficar depois que você receber uma credencial de chave pública:
{
"id": "KEDetxZcUfinhVi6Za5nZQ",
"type": "public-key",
"rawId": "KEDetxZcUfinhVi6Za5nZQ",
"response": {
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiVDF4Q3NueE0yRE5MMktkSzVDTGE2Zk1oRDdPQnFobzZzeXpJbmtfbi1VbyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
"authenticatorData": "j5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGQdAAAAAA",
"signature": "MEUCIQCO1Cm4SA2xiG5FdKDHCJorueiS04wCsqHhiRDbbgITYAIgMKMFirgC2SSFmxrh7z9PzUqr0bK1HZ6Zn8vZVhETnyQ",
"userHandle": "2HzoHm_hY0CjuEESY9tY6-3SdjmNHOoNqaPDcZGzsr0"
}
}
Processar exceções quando não há credenciais disponíveis
Em alguns casos, o usuário pode não ter nenhuma credencial disponível ou não
permitir o uso de uma credencial disponível. Se getCredential()
for invocado e nenhuma credencial for encontrada, uma NoCredentialException
será
retornada. Se isso acontecer, seu código vai processar as instâncias
NoCredentialException
.
Kotlin
try {
val credential = credentialManager.getCredential(credentialRequest)
} catch (e: NoCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
Java
try {
Credential credential = credentialManager.getCredential(credentialRequest);
} catch (NoCredentialException e) {
Log.e("CredentialManager", "No credential available", e);
}
No Android 14 ou em versões mais recentes, é possível reduzir a latência ao mostrar o seletor
de contas usando o método prepareGetCredential()
antes de chamar
getCredential()
.
Kotlin
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
<getPublicKeyCredentialOption>,
<getPasswordOption>
)
)
}
Java
GetCredentialResponse response = credentialManager.prepareGetCredential(
new GetCredentialRequest(
Arrays.asList(
new PublicKeyCredentialOption(),
new PasswordOption()
)
)
);
O método prepareGetCredential()
não invoca elementos da interface. Isso só ajuda
você a realizar o trabalho de preparação para poder iniciar mais tarde a operação
get-credential restante (que envolve interfaces) usando a API getCredential()
.
Os dados em cache são retornados em um objeto PrepareGetCredentialResponse
. Se
houver credenciais, os resultados serão armazenados em cache e você poderá
iniciar mais tarde a API getCredential()
restante para mostrar o seletor
de contas com os dados armazenados em cache.
Fluxos de registro
Você pode registrar um usuário para usar a autenticação com uma chave de acesso ou senha.
Criar uma chave de acesso
Para oferecer aos usuários a opção de criar uma chave de acesso e usá-la na reautenticação,
registre uma credencial de usuário usando um objeto CreatePublicKeyCredentialRequest
.
Kotlin
fun createPasskey(requestJson: String, preferImmediatelyAvailableCredentials: Boolean) { val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest( // Contains the request in JSON format. Uses the standard WebAuthn // web JSON spec. requestJson = requestJson, // Defines whether you prefer to use only immediately available // credentials, not hybrid credentials, to fulfill this request. // This value is false by default. preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials, ) // Execute CreateCredentialRequest asynchronously to register credentials // for a user account. Handle success and failure cases with the result and // exceptions, respectively. coroutineScope.launch { try { val result = credentialManager.createCredential( // Use an activity-based context to avoid undefined system // UI launching behavior context = activityContext, request = createPublicKeyCredentialRequest, ) handlePasskeyRegistrationResult(result) } catch (e : CreateCredentialException){ handleFailure(e) } } } fun handleFailure(e: CreateCredentialException) { when (e) { is CreatePublicKeyCredentialDomException -> { // Handle the passkey DOM errors thrown according to the // WebAuthn spec. handlePasskeyError(e.domError) } is CreateCredentialCancellationException -> { // The user intentionally canceled the operation and chose not // to register the credential. } is CreateCredentialInterruptedException -> { // Retry-able error. Consider retrying the call. } is CreateCredentialProviderConfigurationException -> { // Your app is missing the provider configuration dependency. // Most likely, you're missing the // "credentials-play-services-auth" module. } is CreateCredentialUnknownException -> ... is CreateCredentialCustomException -> { // You have encountered an error from a 3rd-party SDK. If you // make 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.name}") } }
Java
public void createPasskey(String requestJson, boolean preferImmediatelyAvailableCredentials) { CreatePublicKeyCredentialRequest createPublicKeyCredentialRequest = // `requestJson` contains the request in JSON format. Uses the standard // WebAuthn web JSON spec. // `preferImmediatelyAvailableCredentials` defines whether you prefer // to only use immediately available credentials, not hybrid credentials, // to fulfill this request. This value is false by default. new CreatePublicKeyCredentialRequest( requestJson, preferImmediatelyAvailableCredentials); // Execute CreateCredentialRequest asynchronously to register credentials // for a user account. Handle success and failure cases with the result and // exceptions, respectively. credentialManager.createCredentialAsync( // Use an activity-based context to avoid undefined system // UI launching behavior requireActivity(), createPublicKeyCredentialRequest, cancellationSignal, executor, new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() { @Override public void onResult(CreateCredentialResponse result) { handleSuccessfulCreatePasskeyResult(result); } @Override public void onError(CreateCredentialException e) { if (e instanceof CreatePublicKeyCredentialDomException) { // Handle the passkey DOM errors thrown according to the // WebAuthn spec. handlePasskeyError(((CreatePublicKeyCredentialDomException)e).getDomError()); } else if (e instanceof CreateCredentialCancellationException) { // The user intentionally canceled the operation and chose not // to register the credential. } else if (e instanceof CreateCredentialInterruptedException) { // Retry-able error. Consider retrying the call. } else if (e instanceof CreateCredentialProviderConfigurationException) { // Your app is missing the provider configuration dependency. // Most likely, you're missing the // "credentials-play-services-auth" module. } else if (e instanceof CreateCredentialUnknownException) { } else if (e instanceof CreateCredentialCustomException) { // You have encountered an error from a 3rd-party SDK. If // you make 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.getClass().getName()); } } } ); }
Formatar a solicitação JSON
Depois de criar uma chave de acesso, associe-a à conta de um usuário e armazene-a no servidor. O exemplo de código abaixo mostra como formatar a solicitação JSON ao criar uma chave de acesso.
Esta postagem do blog sobre como oferecer a autenticação integrada nos seus apps (link em inglês) mostra como formatar sua solicitação JSON ao criar chaves de acesso e ao autenticar usando essas chaves. Também explica por que as senhas não são uma solução de autenticação eficaz, como aproveitar as credenciais biométricas existentes, como associar seu app a um site seu, como criar chaves de acesso e como autenticar usando chaves de acesso.
{
"challenge": "abc123",
"rp": {
"name": "Credential Manager example",
"id": "credential-manager-test.example.com"
},
"user": {
"id": "def456",
"name": "helloandroid@gmail.com",
"displayName": "helloandroid@gmail.com"
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
},
{
"type": "public-key",
"alg": -257
}
],
"timeout": 1800000,
"attestation": "none",
"excludeCredentials": [
{"id": "ghi789", "type": "public-key"},
{"id": "jkl012", "type": "public-key"}
],
"authenticatorSelection": {
"authenticatorAttachment": "platform",
"requireResidentKey": true,
"residentKey": "required",
"userVerification": "required"
}
}
Definir valores para authenticatorAttachment
O parâmetro authenticatorAttachment
só pode ser definido no momento da criação da
credencial. É possível especificar platform
, cross-platform
ou nenhum valor. Na maioria dos casos,
nenhum valor é recomendado.
platform
: para registrar o dispositivo atual do usuário ou solicitar que o usuário da senha faça upgrade para chaves de acesso após o login, definaauthenticatorAttachment
comoplatform
.cross-platform
: esse valor costuma ser usado ao registrar credenciais de vários fatores e não é usado em um contexto de chave de acesso.- Nenhum valor: para oferecer aos usuários a flexibilidade de criar
chaves de acesso nos dispositivos preferidos deles (como nas configurações da conta), o
parâmetro
authenticatorAttachment
não pode ser especificado quando o usuário decide adicionar uma chave de acesso. Na maioria dos casos, deixar o parâmetro não especificado é a melhor opção.
Impedir a criação de chaves de acesso duplicadas
Liste os IDs de credenciais na matriz opcional excludeCredentials
para evitar
a criação de uma nova chave de acesso, caso já exista uma com o mesmo
provedor.
Processar a resposta JSON
O snippet de código abaixo mostra um exemplo de resposta JSON para criar uma credencial de chave pública. Saiba mais sobre como processar a credencial de chave pública retornada (link em inglês).
{
"id": "KEDetxZcUfinhVi6Za5nZQ",
"type": "public-key",
"rawId": "KEDetxZcUfinhVi6Za5nZQ",
"response": {
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibmhrUVhmRTU5SmI5N1Z5eU5Ka3ZEaVh1Y01Fdmx0ZHV2Y3JEbUdyT0RIWSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
"attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUj5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGRdAAAAAAAAAAAAAAAAAAAAAAAAAAAAEChA3rcWXFH4p4VYumWuZ2WlAQIDJiABIVgg4RqZaJyaC24Pf4tT-8ONIZ5_Elddf3dNotGOx81jj3siWCAWXS6Lz70hvC2g8hwoLllOwlsbYatNkO2uYFO-eJID6A"
}
}
Verificar a origem dos dados do cliente JSON
A origin
(link em inglês) representa o aplicativo ou site de origem de uma
solicitação e é usada pelas chaves de acesso como proteção contra ataques de phishing.
O servidor do app precisa verificar a origem dos dados
do cliente em uma lista de permissões de apps e sites aprovados. Se o servidor
receber uma solicitação de um app ou site de origem não reconhecida,
ela será rejeitada.
No caso da Web, origin
reflete a mesma origem do site (link em inglês) em que
a credencial foi conectada. Por exemplo, considerando um URL de
https://www.example.com:8443/store?category=shoes#athletic
, a origin
é
https://www.example.com:8443
.
Em apps Android, o user agent define a origin
automaticamente como a assinatura do
app de chamada. Essa assinatura precisa ser verificada como uma correspondência no seu servidor para
validar o autor da chamada da API da chave de acesso. A origin
do Android é um URI derivado
do hash SHA-256 do certificado de assinatura do APK, como:
android:apk-key-hash:<sha256_hash-of-apk-signing-cert>
Para encontrar os hashes SHA-256 dos certificados de assinatura de um keystore, execute o seguinte comando do terminal:
keytool -list -keystore <path-to-apk-signing-keystore>
Os hashes SHA-256 estão em um formato hexadecimal delimitado por dois-pontos
(91:F7:CB:F9:D6:81…
), e os valores de origin
do Android são codificados em base64url.
Este exemplo em Python demonstra como converter o formato de hash em um formato
hexadecimal compatível separado por dois-pontos:
import binascii
import base64
fingerprint = '91:F7:CB:F9:D6:81:53:1B:C7:A5:8F:B8:33:CC:A1:4D:AB:ED:E5:09:C5'
print("android:apk-key-hash:" + base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))
Substitua o valor de fingerprint
pelo seu próprio valor. Confira um exemplo
de resultado:
android:apk-key-hash:kffL-daBUxvHpY-4M8yhTavt5QnFEI2LsexohxrGPYU
Você pode fazer a correspondência dessa string como uma origem permitida no seu servidor. Se você tiver vários certificados de assinatura, como certificados para depuração e lançamento, ou vários apps, repita o processo e aceite todas essas origens como válidas no servidor.
Salvar a senha de um usuário
Se o usuário informar um nome de usuário e uma senha durante o fluxo de autenticação do
app, você poderá registrar uma credencial para
autenticá-lo. Para isso, crie um objeto CreatePasswordRequest
:
Kotlin
fun registerPassword(username: String, password: String) { // Initialize a CreatePasswordRequest object. val createPasswordRequest = CreatePasswordRequest(id = username, password = password) // Create credential and handle result. coroutineScope.launch { try { val result = credentialManager.createCredential( // Use an activity based context to avoid undefined // system UI launching behavior. activityContext, createPasswordRequest ) handleRegisterPasswordResult(result) } catch (e: CreateCredentialException) { handleFailure(e) } } }
Java
void registerPassword(String username, String password) { // Initialize a CreatePasswordRequest object. CreatePasswordRequest createPasswordRequest = new CreatePasswordRequest(username, password); // Register the username and password. credentialManager.createCredentialAsync( // Use an activity-based context to avoid undefined // system UI launching behavior requireActivity(), createPasswordRequest, cancellationSignal, executor, new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() { @Override public void onResult(CreateCredentialResponse result) { handleResult(result); } @Override public void onError(CreateCredentialException e) { handleFailure(e); } } ); }
Suporte à recuperação de credenciais
Se um usuário não tiver mais acesso a um dispositivo em que armazenou as credenciais, talvez precise recuperá-las de um backup on-line seguro. Para saber mais sobre como oferecer suporte para esse processo de recuperação de credenciais, leia a seção sobre "Como recuperar o acesso ou adicionar novos dispositivos" na postagem do blog Segurança de chaves de acesso no Gerenciador de senhas do Google (em inglês).
Adicionar suporte a ferramentas de gerenciamento de senhas com o URL conhecido dos endpoints das chaves de acesso
Para integração total e compatibilidade futura com ferramentas de gerenciamento de senhas e credenciais, recomendamos adicionar suporte a URLs conhecidos de endpoints de chave de acesso. Esse é um protocolo aberto para que as partes alinhadas anunciem formalmente o suporte a chaves de acesso e forneçam links diretos para a inscrição e o gerenciamento de chaves de acesso.
- Para uma parte confiável em
https://example.com
, que tem um site com apps Android e iOS, o URL conhecido seriahttps://example.com/.well-known/passkey-endpoints
. Quando o URL é consultado, a resposta precisa usar este esquema:
{ "enroll": "https://example.com/account/manage/passkeys/create" "manage": "https://example.com/account/manage/passkeys" }
Para que esse link seja aberto diretamente no seu app, e não na Web, use Links do app Android.
Confira mais detalhes sobre isso em URLs conhecidos com endpoints de chave de acesso no GitHub (link em inglês).
Mostre qual provedor criou as chaves de acesso para ajudar os usuários a gerenciá-las
Um dos desafios que os usuários enfrentam ao gerenciar várias chaves de acesso associadas a um determinado app é identificar a chave de acesso correta para edição ou exclusão. Para ajudar com esse problema, é recomendável que apps e sites incluam outras informações, como o provedor que criou a credencial, a data de criação e a data de uso mais recente em uma lista de chaves de acesso na tela de configurações do app.As informações do provedor são obtidas examinando o AAGUID associado à chave de acesso correspondente. O AAGUID pode ser encontrado como parte dos dados do autenticador de uma chave de acesso.
Por exemplo, se um usuário criar uma chave de acesso em um dispositivo Android usando o Gerenciador de senhas do Google, o RP receberá um AAGUID parecido com este: "ea9b8d66-4d01-1d21-3ce4-b6b48cb575d4". A parte confiável pode anotar a chave de acesso na lista para indicar que ela foi criada usando o Gerenciador de senhas do Google.
Para mapear um AAGUID a um provedor de chave de acesso, os RPs podem usar um repositório de AAGUIDs fornecido pela comunidade. Procure o AAGUID na lista para encontrar o nome e o ícone do provedor de chave de acesso.
Leia mais sobre a integração do AAGUID.
Resolver erros comuns
Consulte o guia de solução de problemas do Gerenciador de credenciais para conferir códigos de erro comuns, descrições e informações sobre as causas.
Outros recursos
Para saber mais sobre a API Credential Manager e as chaves de acesso, consulte estes recursos:
- Guia de UX de chaves de acesso
- Vídeo: como reduzir a dependência de senhas em apps Android com suporte a chaves de acesso (em inglês).
- Codelab: aprenda a simplificar as jornadas de autenticação usando a API Credential Manager no seu app Android
- App de exemplo: CredentialManager (link em inglês)