---
title: "BiometricPrompt no Android com Kotlin: biometria em 2026"
url: "https://kotlin.dev.br/blog/biometricprompt-android-kotlin-biometria-2026/"
markdown_url: "https://kotlin.dev.br/blog/biometricprompt-android-kotlin-biometria-2026.MD"
description: "Implemente BiometricPrompt com Kotlin: impressão digital, rosto, CryptoObject, Keystore, fallback de PIN e boas práticas de autenticação local no Android."
date: "2026-08-03"
author: "Karina Melo"
---

# BiometricPrompt no Android com Kotlin: biometria em 2026

Implemente BiometricPrompt com Kotlin: impressão digital, rosto, CryptoObject, Keystore, fallback de PIN e boas práticas de autenticação local no Android.


**Resposta rápida:** use a biblioteca **AndroidX Biometric** e a API **BiometricPrompt** para autenticar o usuário com impressão digital, rosto ou o bloqueio de tela do dispositivo, em vez de reinventar UI ou lidar com APIs antigas de fingerprint. Em 2026, o caminho seguro é combinar biometria com **Android Keystore** e, quando o dado for sensível, com `CryptoObject` — assim a chave criptográfica só vira utilizável depois da autenticação bem-sucedida. Biometria autentica a presença do usuário no aparelho; ela **não** substitui login de servidor, sessão, tokens, [passkeys](/blog/passkeys-android-kotlin-credential-manager-2026/) nem a proteção de [dados locais](/blog/seguranca-dados-locais-android-kotlin-2026/).

Apps financeiros, de saúde, carteiras, RH e produtividade pedem “desbloquear com biometria” com frequência. O erro clássico é tratar o sucesso do prompt como prova de identidade global: o sensor só confirma que alguém autorizado no **dispositivo atual** passou pelo desbloqueio biométrico ou pelo fallback de PIN/padrão. Este guia mostra o fluxo prático em Kotlin, quando usar biometria fraca ou forte, como ligar Keystore, como tratar erros e como encaixar o recurso em um produto real.

## O que BiometricPrompt resolve?

`BiometricPrompt` é a API moderna do Android para exibir um diálogo de autenticação biométrica consistente entre fabricantes. Em vez de cada app inventar um modal próprio, o sistema apresenta a interface, o sensor e o fallback de credencial do dispositivo.

Na prática, ela cobre:

- impressão digital;
- reconhecimento facial, quando classificado como biometria forte o suficiente para o nível pedido;
- fallback para PIN, padrão ou senha do aparelho, se você permitir;
- integração opcional com operações criptográficas via `CryptoObject`.

Ela **não** cobre sozinha:

- cadastro de usuário no backend;
- recuperação de conta;
- rotação de refresh token;
- autorização de recursos remotos;
- prova de identidade em outro dispositivo.

Pense biometria como um segundo fator **local** ou como desbloqueio de um cofre no aparelho. Para login sem senha entre dispositivos e sites, o caminho atual é passkey + Credential Manager. Para sessão de API, continue com tokens e [autenticação de backend](/blog/ktor-authentication-jwt-kotlin-2026/).

## Dependência e permissões

No módulo Android:

```kotlin
// build.gradle.kts
dependencies {
    implementation("androidx.biometric:biometric:<versao-atual>")
}
```

Use o version catalog do projeto e confira a release estável compatível com seu `compileSdk` e AndroidX. A biblioteca cuida da UI e da detecção de capacidade; a permissão de fingerprint legada raramente é o ponto central em apps modernos que usam AndroidX Biometric, mas valide o manifesto e o target SDK do seu app.

Antes de mostrar o prompt, sempre pergunte se o dispositivo **pode** autenticar:

```kotlin
val biometricManager = BiometricManager.from(context)
val authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG or
    BiometricManager.Authenticators.DEVICE_CREDENTIAL

when (biometricManager.canAuthenticate(authenticators)) {
    BiometricManager.BIOMETRIC_SUCCESS -> mostrarPrompt()
    BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED ->
        orientarCadastroDeBiometriaOuPin()
    BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE,
    BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
        oferecerFallbackDaAplicacao()
    else -> oferecerFallbackDaAplicacao()
}
```

Essa checagem evita abrir diálogo em aparelho sem sensor, sem biometria cadastrada ou com hardware indisponível. Produto maduro trata esses estados com copy clara, não com crash silencioso.

## Níveis de autenticador: forte, fraca e device credential

A API moderna trabalha com classes de autenticadores:

| Autenticador | Uso típico | Observação |
| --- | --- | --- |
| `BIOMETRIC_STRONG` | pagamentos, liberar chave sensível, ações irreversíveis | exige biometria classificada como Classe 3 |
| `BIOMETRIC_WEAK` | desbloquear tela de app de menor risco | mais permissivo; nem todo sensor fraco serve para CryptoObject forte |
| `DEVICE_CREDENTIAL` | PIN, padrão ou senha do aparelho | útil como fallback ou único fator local |

Para dados sensíveis e operações com Keystore que exigem autenticação do usuário, prefira **BIOMETRIC_STRONG**. Para “abrir o app de notas sem digitar a senha local de novo”, `BIOMETRIC_WEAK` + `DEVICE_CREDENTIAL` pode bastar.

Regra prática de produto:

1. classifique a ação (visualizar saldo x transferir x exportar dados);
2. escolha o autenticador mínimo aceitável;
3. documente o fallback quando biometria falha ou não existe;
4. nunca esconda a ausência de fallback se a ação for crítica.

## Implementação básica com Kotlin e Fragment/Activity

`BiometricPrompt` precisa de um `FragmentActivity` ou `Fragment` e de um `Executor` para callbacks. O padrão limpo em Kotlin:

```kotlin
class BiometricGate(
    private val activity: FragmentActivity,
) {
    private val executor = ContextCompat.getMainExecutor(activity)

    fun authenticate(
        title: String,
        subtitle: String,
        onSuccess: () -> Unit,
        onError: (code: Int, message: CharSequence) -> Unit,
        onFailed: () -> Unit,
    ) {
        val callback = object : BiometricPrompt.AuthenticationCallback() {
            override fun onAuthenticationSucceeded(
                result: BiometricPrompt.AuthenticationResult,
            ) {
                onSuccess()
            }

            override fun onAuthenticationError(
                errorCode: Int,
                errString: CharSequence,
            ) {
                onError(errorCode, errString)
            }

            override fun onAuthenticationFailed() {
                onFailed()
            }
        }

        val prompt = BiometricPrompt(activity, executor, callback)
        val info = BiometricPrompt.PromptInfo.Builder()
            .setTitle(title)
            .setSubtitle(subtitle)
            .setAllowedAuthenticators(
                BiometricManager.Authenticators.BIOMETRIC_STRONG or
                    BiometricManager.Authenticators.DEVICE_CREDENTIAL,
            )
            .build()

        prompt.authenticate(info)
    }
}
```

Pontos que costumam quebrar em code review:

- chamar o prompt fora do ciclo de vida ativo da Activity/Fragment;
- misturar `setNegativeButtonText` com `DEVICE_CREDENTIAL` de forma inválida para a combinação escolhida;
- tratar `onAuthenticationFailed` como erro terminal — ele só indica uma tentativa rejeitada, o diálogo pode continuar aberto;
- ignorar `ERROR_USER_CANCELED` e `ERROR_NEGATIVE_BUTTON` e relançar o prompt em loop.

## CryptoObject e Android Keystore: o padrão que importa

O maior salto de segurança não é “mostrar o dialog”. É amarrar a biometria a uma **chave** que só opera depois da autenticação.

Fluxo recomendado para token local, segredo de cofre ou chave de criptografia de Room/SQLCipher:

1. crie uma chave no Android Keystore com `setUserAuthenticationRequired(true)`;
2. configure validade da autenticação (por operação ou por alguns segundos, conforme a API e o caso);
3. inicie um `Cipher` em modo encrypt/decrypt com essa chave;
4. passe o `Cipher` em um `BiometricPrompt.CryptoObject`;
5. só use o `Cipher` retornado em `AuthenticationResult` após sucesso.

Esboço conceitual:

```kotlin
val cipher = cipherForKeystoreKey(keyAlias)
val cryptoObject = BiometricPrompt.CryptoObject(cipher)

prompt.authenticate(promptInfo, cryptoObject)

// no sucesso:
val readyCipher = result.cryptoObject?.cipher
    ?: error("Cipher indisponível após biometria")
val plaintext = readyCipher.doFinal(ciphertext)
```

Sem `CryptoObject`, um app malicioso ou um fluxo descuidado pode “aceitar biometria” e liberar dados que estavam apenas escondidos por um boolean em memória. Com Keystore + biometria, o sistema operacional e o hardware de segurança entram na equação.

Se o seu app já usa [EncryptedSharedPreferences, SQLCipher ou tokens locais](/blog/seguranca-dados-locais-android-kotlin-2026/), avalie se a chave mestra deve exigir autenticação do usuário. Nem todo cache precisa disso; refresh token e exportação de dados pessoais quase sempre merecem.

## Onde biometria se encaixa no produto

### 1. Desbloqueio do app (app lock)

O usuário já autenticou no servidor. A biometria evita reentrada de senha local ao voltar do background. Combine com timeout de sessão em memória e limpeza de campos sensíveis ao ir para segundo plano.

### 2. Confirmação de ação sensível

Transferência, exclusão de conta, revelar CVV, assinar documento ou exportar relatório. Aqui biometria funciona como step-up local. Ainda assim, operações remotas críticas devem ter autorização no backend.

### 3. Desbloquear segredo local

Chave de cofre, token offline, credencial de VPN corporativa. Este é o melhor casamento com Keystore.

### 4. Não use biometria para

- provar identidade em suporte (“o app desbloqueou, então é o titular”);
- substituir consentimento LGPD;
- autenticar em outro aparelho;
- esconder má arquitetura de sessão.

Para login moderno sem senha, leia também o guia de [passkeys com Credential Manager](/blog/passkeys-android-kotlin-credential-manager-2026/). Biometria do dispositivo e passkeys se complementam: uma protege o cofre local e a experiência no aparelho; a outra autentica o usuário no serviço com criptografia de chave pública.

## Tratamento de erros e UX em português do Brasil

Mensagens genéricas destroem conversão. Separe:

- **cancelamento do usuário** — não mostre “erro de segurança”;
- **tentativa falha** — “Não reconhecemos a biometria. Tente de novo.”;
- **muitas tentativas** — ofereça PIN do aparelho ou senha do app;
- **biometria não cadastrada** — deep link para configurações quando fizer sentido;
- **hardware indisponível** — fallback imediato;
- **lockout temporário** — explique o tempo de espera sem culpar o usuário.

Do ponto de vista de acessibilidade, o diálogo do sistema já carrega boa parte da experiência. Seu app ainda precisa de:

- labels claros no botão que abre o prompt;
- alternativa não biométrica para quem não pode ou não quer cadastrar sensor;
- não depender só de ícone de digital sem texto;
- respeitar políticas corporativas que desabilitam biometria em MDM.

## Testes, emulador e QA

Testar biometria exige disciplina:

- use emulador com fingerprint virtual para fluxos felizes e falhas;
- cubra `canAuthenticate` com todos os estados relevantes;
- teste rotação de tela e process death com o prompt aberto;
- valide que o segredo **não** é descriptografado antes do callback de sucesso;
- em UI tests, isole o gate atrás de uma interface para não acoplar Espresso/Compose Test ao sensor real;
- no dispositivo físico, valide OEM diferentes — a qualidade do face unlock e a classificação forte/fraca variam.

Em pipelines, prefira testes de unidade no orquestrador (decidir se mostra prompt, qual autenticador, qual fallback) e testes instrumentados smoke em nightly, não em todo PR bloqueante.

## Checklist de produção

Antes de liberar biometria em produção, confira:

1. `canAuthenticate` trata todos os estados relevantes;
2. título e subtítulo do prompt explicam **por que** a biometria é pedida;
3. ações sensíveis usam `BIOMETRIC_STRONG` quando necessário;
4. dados sensíveis passam por Keystore/`CryptoObject`, não por flag booleana;
5. logout limpa chaves de sessão e caches em memória;
6. logs não gravam templates biométricos nem material de chave;
7. política de privacidade e tela de permissões/explicação estão alinhadas à [LGPD no Android](/blog/lgpd-android-kotlin-2026/);
8. há fallback utilizável para quem não cadastrou biometria;
9. o backend continua sendo a fonte de verdade para autorização remota;
10. o time documentou o que acontece em troca de aparelho e em reset de fábrica.

## Biometria, carreira e entrevistas Android

Em entrevistas Android/Kotlin, biometria aparece como proxy de maturidade em segurança móvel. Costuma cair junto com Keystore, armazenamento local, deep links e autenticação. Saber só chamar `BiometricPrompt` não basta: o avaliador quer ouvir sobre classes de autenticador, CryptoObject, diferença entre biometria local e login de servidor, e trade-offs de UX.

Se você está montando portfólio, um app de notas ou carteira demo com app lock biométrico + criptografia local pesa mais do que mais uma lista de CRUD. Combine com [roadmap Android](/carreira/roadmap-dev-android/), [preparação de entrevista](/carreira/como-preparar-entrevista-kotlin-android/) e práticas de [segurança local](/blog/seguranca-dados-locais-android-kotlin-2026/).

## Perguntas frequentes

### BiometricPrompt funciona com Jetpack Compose?

Sim. Compose não substitui o prompt do sistema. Você dispara o fluxo a partir de um `FragmentActivity` hospedeiro, ViewModel ou wrapper, e reage ao resultado atualizando estado Compose. O diálogo em si continua sendo do AndroidX Biometric.

### Posso usar biometria no lugar de senha do meu backend?

Não como prova única entre dispositivos. Biometria local confirma presença no aparelho atual. Para autenticação no serviço, use sessão, OAuth, JWT ou passkeys. Biometria pode proteger o acesso à sessão já estabelecida ou a um segredo local.

### Face unlock conta como biometria forte?

Depende do dispositivo e da classificação do autenticador. Nem todo reconhecimento facial atende `BIOMETRIC_STRONG`. Por isso a checagem com `BiometricManager` e a escolha explícita de autenticadores importam mais do que assumir “tem sensor de rosto”.

### Preciso guardar a impressão digital no meu servidor?

Não. O app **não** recebe o template biométrico do usuário para enviar à API. O sistema valida no dispositivo e devolve sucesso/erro (e, com CryptoObject, um cipher desbloqueado). Guardar biometria bruta no backend não é o modelo do Android e cria risco desnecessário.

### Qual a diferença para passkeys?

Passkeys autenticam o usuário no **serviço** com par de chaves e WebAuthn. BiometricPrompt autentica o usuário no **dispositivo** para liberar uma ação ou um segredo local. Muitos fluxos de passkey usam biometria do aparelho na UX, mas a garantia criptográfica perante o servidor vem da passkey, não do callback isolado do BiometricPrompt.

## Conclusão

Em 2026, biometria bem feita no Android com Kotlin é menos sobre animar um ícone de digital e mais sobre **governança de autenticação local**: escolher o autenticador certo, tratar estados de hardware, amarrar segredos ao Keystore e deixar claro o que a biometria prova — e o que ela não prova. Comece pelo gate de `canAuthenticate`, implemente `BiometricPrompt` com callbacks previsíveis, eleve o nível com `CryptoObject` nas ações sensíveis e conecte o recurso a uma estratégia maior de segurança e produto.

Se o próximo passo do seu app for login sem senha entre plataformas, siga para [passkeys com Credential Manager](/blog/passkeys-android-kotlin-credential-manager-2026/). Se a dor for proteger Room, tokens e cache, volte ao guia de [segurança de dados locais](/blog/seguranca-dados-locais-android-kotlin-2026/). E se a meta for vaga Android, use esse tipo de feature no portfólio com decisão de arquitetura documentada, não só com print do dialog.
