# Cómo autenticar con biometría (huella / Face ID)

> Verificar disponibilidad y autenticar al usuario con huella digital, Face ID o Windows Hello.

Source: https://crossfly.dev/es/docs/cookbook/device/biometria — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Cómo autenticar con biometría (huella / Face ID)

**Propósito.** Proteger una acción sensible pidiendo **autenticación biométrica** (huella, Face ID/Touch
ID, o Windows Hello en el escritorio). El resultado llega por callback, de forma asíncrona.

## APIs usadas
- `boolean Biometry.isAvailable()` — `true` si el dispositivo tiene al menos un método biométrico disponible. **Llámalo siempre antes** de autenticar.
- `void Biometry.authenticate(String reason, String cancel, boolean onlyBiometric, Biometry.Callback callback)` — muestra la UI nativa de biometría.
  - `reason` — texto que explica por qué es necesaria la autenticación.
  - `cancel` — etiqueta del botón de cancelar.
  - `onlyBiometric` — `true` = solo biometría (sin fallback a PIN/contraseña); `false` = permite PIN/contraseña.
- `Biometry.Callback.onResult(AuthResult result, String message)` — resultado asíncrono.
- `Biometry.AuthResult` (enum) — `SUCCESS`, `FAILURE`, `CANCELLED`, `ERROR`.

> **Nota.** El callback llega **fuera del paint thread** — envuelve cualquier actualización de UI en
> `Component.onUI(...)`. Soporte: Android (BiometricPrompt), iOS (Face ID/Touch ID), escritorio limitado
> (Windows Hello). Los datos biométricos nunca salen del dispositivo — solo se devuelve el resultado.

## Ejemplo completo (copiar, pegar y ejecutar)

```java
package com.exemplo;

import dev.crossfly.ui.*;                   // Window, Component, Button, Label
import dev.crossfly.ui.layout.*;            // VerticalLayout
import dev.crossfly.device.*;               // Biometry, Biometry.AuthResult

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Label resultado = new Label("");
      add(LAY_AUTO, resultado);

      Button acao = new Button("Autenticar");
      acao.onAction(c ->
      {
         if (Biometry.isAvailable())
         {
            Biometry.authenticate(
               "Autentique-se para acessar sua conta",  // reason
               "Cancelar",                               // cancel
               false,                                    // onlyBiometric=false → permite PIN/contraseña
               (result, message) -> Component.onUI(() ->   // callback fuera de la paint thread
               {
                  switch (result)
                  {
                     case SUCCESS:   resultado.setText("Acesso liberado");        break;
                     case FAILURE:   resultado.setText("Falhou: " + message);     break;
                     case CANCELLED: resultado.setText("Cancelado");              break;
                     case ERROR:     resultado.setText("Erro: " + message);       break;
                  }
               }));
         }
         else
         {
            resultado.setText("Sem biometria disponível");   // recurre a contraseña/PIN de la aplicación
         }
      });
      add(LAY_AUTO, acao);
   }
}
```

> El fragmento de abajo muestra **solo el núcleo**. Para ejecutarlo, colócalo en el esqueleto `MainWindow` de arriba.

## Fragmento mínimo

```java
// verificado en la fuente: Biometry.java (isAvailable, authenticate, Callback.onResult, AuthResult)
import dev.crossfly.device.*;              // Biometry, Biometry.AuthResult
import dev.crossfly.ui.*;                  // Component (onUI)

if (Biometry.isAvailable()) {
   Biometry.authenticate(
      "Autentique-se para acessar sua conta",  // reason
      "Cancelar",                               // cancel
      false,                                    // onlyBiometric=false → permite PIN/contraseña
      (result, message) -> Component.onUI(() -> {   // callback fuera de la paint thread
         switch (result) {
            case SUCCESS:   liberarAcesso();                     break;
            case FAILURE:   mostrarErro("Falhou: " + message);   break;
            case CANCELLED: /* el usuario canceló */               break;
            case ERROR:     mostrarErro("Erro: " + message);     break;
         }
      }));
} else {
   // Sin biometría: recurre a contraseña/PIN de la aplicación
}
```

## Profundiza
- Guía de biometría: [Biometría](/docs/data-and-services/device-biometry)
