Com suporte para chaves de acesso, login federado e provedores de autenticação de terceiros, o Gerenciador de credenciais é a API recomendada para autenticação no Android que oferece um ambiente seguro e conveniente que permite aos usuários sincronizar e gerenciar as próprias credenciais. Para desenvolvedores que usam credenciais do FIDO2 locais, atualize seu app para oferecer suporte à autenticação de chaves de acesso pela integração com a API Credential Manager. Este documento descreve como migrar seu projeto do FIDO2 para o Gerenciador de credenciais.
Motivos para migrar do FIDO2 para o Gerenciador de credenciais
Na maioria dos casos, você precisa migrar o provedor de autenticação do seu app Android para o Gerenciador de credenciais: Os motivos para essa migração incluem:
- Suporte a chaves de acesso: o Gerenciador de credenciais oferece suporte a chaves de acesso, um novo mecanismo de autenticação sem senha que é mais seguro e fácil de usar do que senhas.
- Vários métodos de login: o Gerenciador de credenciais oferece suporte a vários métodos de login, incluindo senhas, chaves de acesso e métodos de login federados. Isso facilita a autenticação dos usuários no seu app, independente do método de autenticação preferido.
- Suporte a provedores de credenciais de terceiros: no Android 14 e versões mais recentes, o Gerenciador de credenciais oferece suporte a vários provedores de credenciais de terceiros. Isso significa que seus usuários podem usar as credenciais atuais de outros provedores para fazer login no seu app.
- Experiência do usuário consistente:o Gerenciador de credenciais oferece uma experiência do usuário mais consistente para autenticação em todos os apps e mecanismos de login. Isso facilita que os usuários entendam e usem o fluxo de autenticação do app.
Para iniciar a migração do FIDO2 para o Gerenciador de credenciais, siga as etapas abaixo.
Atualizar dependências
Atualize o plug-in do Kotlin no build.gradle do projeto para a versão 1.8.10 ou mais recente.
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }No
build.gradledo projeto, atualize as dependências para usar as versões mais recentes das bibliotecas do Gerenciador de credenciais e da autenticação do Google Play Services.dependencies { // ... // Credential Manager: implementation 'androidx.credentials:credentials:<latest-version>' // Play Services Authentication: // Optional - needed for credentials support from play services, for devices running // Android 13 and below: implementation 'androidx.credentials:credentials-play-services-auth:<latest-version>' // ... }Substitua a inicialização do FIDO pela inicialização do Gerenciador de credenciais. Adicione essa declaração na classe que você usa para criação de chaves de acesso e métodos de login:
val credMan = CredentialManager.create(context)
Criar chaves de acesso
Você precisará criar uma nova chave de acesso, associá-la à conta de um usuário e armazenar a chave pública no servidor para que o usuário possa fazer login com ela. Configure seu app com esse recurso atualizando as chamadas de função de registro.
Para acessar os parâmetros necessários que são enviados ao método
createCredential()durante a criação da chave de acesso, adicionename("residentKey").value("required")(conforme descrito na especificação WebAuthn) à chamada de servidorregisterRequest().suspend fun registerRequest() { // ... val call = client.newCall( Builder() .method( "POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("residentKey").value("required") } } ).build() ) // ... }Defina o tipo de
returnpararegisterRequest()e todas as funções filhas comoJSONObject.suspend fun registerRequest(sessionId: String): ApiResult<JSONObject> { val call = client.newCall( Builder() .url("$BASE_URL/<your api url>") .addHeader("Cookie", formatCookie(sessionId)) .method( "POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("authenticatorAttachment").value("platform") name("userVerification").value("required") name("residentKey").value("required") } } ).build() ) val response = call.await() return response.result("Error calling the api") { parsePublicKeyCredentialCreationOptions( body ?: throw ApiException("Empty response from the api call") ) } }Remova com segurança da sua visualização todos os métodos que processam chamadas de tela de início de intents e de resultados de atividades.
Como
registerRequest()agora retorna umJSONObject, não é necessário criar umaPendingIntent. Substitua a intent retornada por umJSONObject. Atualize as chamadas da tela de início da intent para chamarcreateCredential()na API Credential Manager. Chame o método de APIcreateCredential().suspend fun createPasskey( activity: Activity, requestResult: JSONObject ): CreatePublicKeyCredentialResponse? { val request = CreatePublicKeyCredentialRequest(requestResult.toString()) var response: CreatePublicKeyCredentialResponse? = null try { response = credMan.createCredential( request = request as CreateCredentialRequest, context = activity ) as CreatePublicKeyCredentialResponse } catch (e: CreateCredentialException) { showErrorAlert(activity, e) return null } return response }Quando a chamada for concluída, envie a resposta de volta ao servidor. A solicitação e a resposta dessa chamada são semelhantes à implementação do FIDO2. Portanto, nenhuma mudança é necessária.
Autenticar com chaves de acesso
Depois de configurar a criação da chave de acesso, você pode configurar seu app para permitir que os usuários façam login e se autentiquem usando as chaves de acesso. Para fazer isso, atualize o código de autenticação para processar os resultados do Gerenciador de credenciais e implemente uma função para autenticar usando chaves de acesso.
- A chamada de solicitação de login ao servidor para receber as informações necessárias a serem
enviadas à solicitação
getCredential()é a mesma que a implementação do FIDO2. Nenhuma mudança é necessária. Semelhante à chamada de solicitação de registro, a resposta retornada está no formato JSONObject.
/** * @param sessionId The session ID to be used for the sign-in. * @param credentialId The credential ID of this device. * @return a JSON object. */ suspend fun signinRequest(): ApiResult<JSONObject> { val call = client.newCall( Builder().url( buildString { append("$BASE_URL/signinRequest") } ).method("POST", jsonRequestBody {}) .build() ) val response = call.await() return response.result("Error calling /signinRequest") { parsePublicKeyCredentialRequestOptions( body ?: throw ApiException("Empty response from /signinRequest") ) } } /** * @param sessionId The session ID to be used for the sign-in. * @param response The JSONObject for signInResponse. * @param credentialId id/rawId. * @return A list of all the credentials registered on the server, * including the newly-registered one. */ suspend fun signinResponse( sessionId: String, response: JSONObject, credentialId: String ): ApiResult<Unit> { val call = client.newCall( Builder().url("$BASE_URL/signinResponse") .addHeader("Cookie", formatCookie(sessionId)) .method( "POST", jsonRequestBody { name("id").value(credentialId) name("type").value(PUBLIC_KEY.toString()) name("rawId").value(credentialId) name("response").objectValue { name("clientDataJSON").value( response.getString("clientDataJSON") ) name("authenticatorData").value( response.getString("authenticatorData") ) name("signature").value( response.getString("signature") ) name("userHandle").value( response.getString("userHandle") ) } } ).build() ) val apiResponse = call.await() return apiResponse.result("Error calling /signingResponse") { } }Remova com segurança qualquer método que processe a tela de início de intents e chamadas de resultado de atividades da sua visualização.
Como
signInRequest()agora retorna umJSONObject, não é necessário criar umaPendingIntent. Substitua a intent retornada por umJSONObjecte chamegetCredential()nos métodos da API.suspend fun getPasskey( activity: Activity, creationResult: JSONObject ): GetCredentialResponse? { Toast.makeText( activity, "Fetching previously stored credentials", Toast.LENGTH_SHORT ) .show() var result: GetCredentialResponse? = null try { val request = GetCredentialRequest( listOf( GetPublicKeyCredentialOption( creationResult.toString(), null ), GetPasswordOption() ) ) result = credMan.getCredential(activity, request) if (result.credential is PublicKeyCredential) { val publicKeycredential = result.credential as PublicKeyCredential Log.i("TAG", "Passkey ${publicKeycredential.authenticationResponseJson}") return result } } catch (e: Exception) { showErrorAlert(activity, e) } return result }Depois que a chamada for bem-sucedida, envie a resposta de volta ao servidor para validar e autenticar o usuário. Os parâmetros de solicitação e resposta para essa chamada de API são semelhantes à implementação do FIDO2. Portanto, nenhuma mudança é necessária.
Outros recursos
- Referência de exemplo do Gerenciador de credenciais
- Codelab do Gerenciador de credenciais
- Como usar a API Credential Manager para simplificar a autenticação nos seus apps com chaves de acesso
- Codelab do FIDO2