Fazer o login do usuário com o Gerenciador de credenciais

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 recurso "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:

Enviar feedback

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.

Pré-requisitos

Para usar o Gerenciador de credenciais, siga 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:

Groovy

dependencies {
    implementation "androidx.credentials:credentials:1.0.0-alpha02"

    // optional - needed for credentials support from play services, for devices running
    // Android 13 and below.
    implementation "androidx.credentials:credentials-play-services-auth:1.0.0-alpha02"
}

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.0.0-alpha02")

    // optional - needed for credentials support from play services, for devices running
    // Android 13 and below.
    implementation("androidx.credentials:credentials-play-services-auth:1.0.0-alpha02")
}

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:

  1. 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 pacote com.example podem compartilhar credenciais de login, crie um arquivo chamado assetlinks.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 a string delegate_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ínio www.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.
  2. 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 em https://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.

  3. 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 recupere /.well-known/assetlinks.json. A maioria dos sites pode simplesmente 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/
    

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.

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:

  1. 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);
  2. Crie a solicitação de login usando as opções extraídas da etapa anterior:

    Kotlin

    val getCredRequest = GetCredentialRequest(
        listOf(getPasswordOption, getPublicKeyCredentialOption)
    )

    Java

    GetCredentialRequest getCredRequest = new GetCredentialRequest.Builder()
        .addCredentialOption(getPasswordOption)
        .addCredentialOption(getPublicKeyCredentialOption)
        .build();
  3. 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 onSuccess(GetCredentialResponse result) {
                handleSignIn(result);
            }
    
            @Override
            public void onFailure(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"
  }
}

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.

Ao chamar a API Credential Manager pela primeira vez, defina preferImmediatelyAvailableCredentials como true. O método preferImmediatelyAvailableCredentials define se você prefere usar somente credenciais disponíveis imediatamente, e não credenciais híbridas (link em inglês) para atender a essa solicitação. Se definido como true (verdadeiro), a API Credential Manager não mostrará uma entrada remota se as credenciais não estiverem disponíveis. Por padrão, esse valor é false.

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 snippet abaixo mostra um exemplo de 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 chaves de acesso. 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": "nhkQXfE59Jb97VyyNJkvDiXucMEvltduvcrDmGrODHY",
  "rp": {
    "name": "CredMan App Test",
    "id": "credential-manager-app-test.glitch.me"
  },
  "user": {
    "id": "2HzoHm_hY0CjuEESY9tY6-3SdjmNHOoNqaPDcZGzsr0",
    "name": "helloandroid@gmail.com",
    "displayName": "helloandroid@gmail.com"
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    },
    {
      "type": "public-key",
      "alg": -257
    }
  ],
  "timeout": 1800000,
  "attestation": "none",
  "excludeCredentials": [],
  "authenticatorSelection": {
    "authenticatorAttachment": "platform",
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

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

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 (link em inglês).

Adicionar suporte a ferramentas de gerenciamento de senha com o URL conhecido dos endpoints de chave de acesso

Para integração total e compatibilidade futura com ferramentas de gerenciamento de senhas e credenciais, recomendamos adicionar suporte a URLs conhecidos com 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.

  1. Como exemplo de uma parte confiável no endereço https://example.com, que tem um site com apps Android e iOS, o URL conhecido seria https://example.com/.well-known/passkey-endpoints.

  2. 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"
    }
    
  3. Para que esse link seja aberto diretamente no seu app, e não na Web, use Links do app Android.

  4. Confira mais detalhes sobre isso em URLs conhecidos com endpoints de chave de acesso no GitHub (link em inglês).

Resolver erros comuns

A tabela abaixo apresenta códigos e descrições de erros comuns, além de fornecer algumas informações sobre as causas:

Código do erro e descrição Causa
On Begin Sign In Failure: 16: o autor da chamada foi bloqueado temporariamente porque muitas solicitações de login foram canceladas.

Se encontrar esse período de bloqueio de 24 horas durante o desenvolvimento, você pode limpar o armazenamento de apps do Google Play Services para redefini-lo.

Como alternativa, para ativar esse período de bloqueio em um dispositivo de teste ou emulador, abra o app Telefone e insira este código: *#*#66382723#*#*. O app Telefone vai limpar todas as entradas e pode até fechar, mas nenhuma mensagem de confirmação vai aparecer.

On Begin Sign In Failure: 8: erro interno desconhecido.
  1. A Conta do Google não está configurada corretamente no dispositivo.
  2. O JSON da chave de acesso está sendo criado incorretamente.
CreatePublicKeyCredentialDomException: a solicitação recebida não pode ser validada. O ID do pacote do app não está registrado no seu servidor. Corrija isso na integração do lado do servidor.
CreateCredentialUnknownException: durante o salvamento de senha, foi encontrada uma resposta de falha de senha de um toque 16: ignorando o salvamento de senhas, já que o usuário provavelmente receberá uma solicitação de preenchimento automático do Android. Esse erro ocorre apenas no Android 13 e versões anteriores e apenas se o Google for o provedor de preenchimento automático. Nesse caso, o preenchimento automático mostra uma solicitação de salvamento, e a senha é salva no Gerenciador de senhas do Google. As credenciais salvas usando o Preenchimento automático do Google são compartilhadas bidirecionalmente com a API Credential Manager. Como resultado, esse erro pode ser ignorado com segurança.

Outros recursos

Para saber mais sobre a API Credential Manager e as chaves de acesso, consulte estes recursos: