La autenticación biométrica en Flutter es una de esas features que, bien implementada, mejora dos cosas a la vez: seguridad y UX. El usuario desbloquea con huella o Face ID en segundos y tú reduces fricción sin caer en atajos inseguros como “guardar la password” o inventarte un PIN pobre.
En este tutorial vamos a implementar autenticación biométrica en Flutter de forma completa: desde dependencias y permisos en Android/iOS, hasta un helper reutilizable y una pantalla de login que muestra el botón biométrico solo cuando tiene sentido. También vamos a cubrir lo más importante para producción: qué protege realmente la biometría, qué no, y cómo evitar errores típicos.

Qué protege de verdad la autenticación biométrica en Flutter
Antes de tocar código, la regla de oro: la biometría no “logea” contra tu backend. La autenticación biométrica en Flutter lo que hace es pedirle al sistema operativo que verifique que el usuario es quien dice ser (con hardware y APIs del dispositivo) y devolver un true/false.
Lo correcto es usar esa verificación para:
- Desbloquear una sesión ya existente (por ejemplo, un refresh token almacenado en Keychain/Keystore)
- Confirmar operaciones sensibles (pago, transferencia, cambio de email, exportación de datos)
- Reautenticar al abrir la app tras X minutos en background
Lo incorrecto es:
- Tratar la biometría como sustituto de credenciales o de una sesión validada por servidor
- Guardar “algo equivalente a una password” en texto plano y protegerlo solo con biometría
Planteado así, la autenticación biométrica en Flutter se convierte en un “unlock” seguro y cómodo.
Cómo funciona el flujo biométrico en Flutter
El flujo típico de autenticación biométrica en Flutter es:
- UI Flutter solicita autenticación
- Plugin
local_authdelega en el sistema operativo - iOS/Android invoca el sensor (Face ID, Touch ID, huella)
- El sistema devuelve éxito o fallo
- Tu app decide qué hacer (abrir sesión, mostrar error, pedir fallback) Secure Biometric Authentication…
Este diseño tiene una ventaja clave: tu app no gestiona biometría directamente. Ni almacenas huellas ni “ves” la cara. Eso simplifica compliance y reduce superficie de ataque.
Requisitos previos
Para implementar autenticación biométrica en Flutter:
- Proyecto Flutter creado
- Dispositivo real para testing (en simulador puede ser poco fiable)
- Biometría configurada en el dispositivo (si el usuario no la ha activado, no hay magia)
Paso 1. Crear el proyecto y añadir la dependencia
Creamos el proyecto:
flutter create biometrics_poc
cd biometrics_poc
Añadimos la dependencia en pubspec.yaml:
dependencies:
flutter:
sdk: flutter
local_auth: ^3.0.0
Instalamos:
flutter pub get
Con esto ya podemos empezar la autenticación biométrica en Flutter.
Paso 2. Configurar permisos en Android
En Android, necesitas declarar permisos para biometría. Edita:
android/app/src/main/AndroidManifest.xml
Dentro de <manifest> añade:
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-feature android:name="android.hardware.fingerprint" android:required="false" />
USE_BIOMETRICcubre métodos modernosUSE_FINGERPRINTcubre compatibilidad con implementaciones más antiguasuses-featureconrequired="false"evita que Play Store marque tu app como incompatible en dispositivos sin sensor Secure Biometric Authentication…
Este punto es básico para que la autenticación biométrica en Flutter sea “robusta” y no te rompa distribución.
Paso 3. Configurar permisos en iOS
En iOS debes incluir la razón de uso de Face ID/Touch ID. Edita:
ios/Runner/Info.plist
Añade:
<key>NSFaceIDUsageDescription</key>
<string>Autentícate para continuar.</string>
Este string es el texto que verá el usuario cuando el sistema pida permiso. Si es vago o raro, baja la confianza. Si es claro, sube la conversión del primer intento. Secure Biometric Authentication…
Con esto ya tienes la base para autenticación biométrica en Flutter en iOS.

Paso 4. Crear un helper reutilizable
Para que la autenticación biométrica en Flutter no quede pegada a una pantalla, conviene encapsular la lógica en un helper.
Crea: lib/helpers/biometric_helper.dart
import 'package:local_auth/local_auth.dart';
class BiometricHelper {
final LocalAuthentication _localAuth = LocalAuthentication();
Future<bool> isDeviceCapable() async {
try {
return await _localAuth.isDeviceSupported();
} catch (_) {
return false;
}
}
Future<bool> isBiometricEnabled() async {
try {
final available = await _localAuth.getAvailableBiometrics();
return available.isNotEmpty;
} catch (_) {
return false;
}
}
Future<String?> getBiometricTypeLabel() async {
try {
final available = await _localAuth.getAvailableBiometrics();
if (available.isEmpty) return null;
if (available.contains(BiometricType.face)) {
return 'Face ID';
}
if (available.contains(BiometricType.fingerprint)) {
return 'Touch ID';
}
return 'Biometría';
} catch (_) {
return null;
}
}
Future<bool> authenticate({required String reason}) async {
try {
return await _localAuth.authenticate(
localizedReason: reason,
);
} catch (_) {
return false;
}
}
}
Este helper cubre lo esencial para autenticación biométrica en Flutter:
- Capacidad del dispositivo
- Biometría configurada
- Etiqueta para UI
- Trigger de autenticación Secure Biometric Authentication…
Paso 5. Integrar la autenticación biométrica en la UI de login
Ahora montamos una pantalla de login que:
- Comprueba estado biométrico al cargar
- Muestra botón biométrico solo si procede
- Ejecuta autenticación y actúa en consecuencia
Ejemplo de LoginPage minimalista:
import 'package:flutter/material.dart';
import 'helpers/biometric_helper.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _biometricHelper = BiometricHelper();
bool _isDeviceCapable = false;
bool _isBiometricEnabled = false;
String? _biometricTypeLabel;
bool _loading = false;
String? _message;
bool get _canUseBiometric => _isDeviceCapable && _isBiometricEnabled;
@override
void initState() {
super.initState();
_checkBiometricStatus();
}
Future<void> _checkBiometricStatus() async {
final capable = await _biometricHelper.isDeviceCapable();
final enabled = await _biometricHelper.isBiometricEnabled();
final label = await _biometricHelper.getBiometricTypeLabel();
if (!mounted) return;
setState(() {
_isDeviceCapable = capable;
_isBiometricEnabled = enabled;
_biometricTypeLabel = label;
});
}
Future<void> _handleBiometricLogin() async {
setState(() {
_loading = true;
_message = null;
});
final ok = await _biometricHelper.authenticate(
reason: 'Autentícate para iniciar sesión',
);
if (!mounted) return;
setState(() {
_loading = false;
_message = ok ? 'Autenticación correcta' : 'No se ha podido autenticar';
});
if (ok) {
// Aquí normalmente desbloqueas un token local y navegas al home.
// Navigator.of(context).pushReplacement(...);
}
}
@override
Widget build(BuildContext context) {
final biometricText = _biometricTypeLabel != null
? 'Entrar con $_biometricTypeLabel'
: 'Entrar con biometría';
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 16),
// Login clásico (placeholder)
TextField(
decoration: const InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
),
const SizedBox(height: 12),
TextField(
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _loading ? null : () {},
child: const Text('Entrar'),
),
const SizedBox(height: 24),
if (_canUseBiometric)
OutlinedButton(
onPressed: _loading ? null : _handleBiometricLogin,
child: _loading
? const SizedBox(
height: 18,
width: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: Text(biometricText),
)
else
Text(
_isDeviceCapable
? 'Biometría no configurada en el dispositivo'
: 'Dispositivo sin soporte biométrico',
),
if (_message != null) ...[
const SizedBox(height: 12),
Text(_message!),
],
],
),
),
);
}
}
Este patrón es el “mínimo viable” para autenticación biométrica en Flutter sin ensuciar la UI con lógica de plataforma.

Paso 6. Conectar la pantalla en main.dart
En main.dart:
import 'package:flutter/material.dart';
import 'login_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: LoginPage(),
);
}
}
Ya tienes autenticación biométrica en Flutter funcionando end-to-end.
Paso 7. Testing de la autenticación biométrica en Flutter
Para testear bien:
- Android: dispositivo físico con huella o face unlock activado. Deberías ver el prompt del sistema al pulsar el botón biométrico
- iOS: dispositivo físico con Face ID o Touch ID configurado. Al pulsar, debería saltar el diálogo del sistema
- Simuladores: pueden fallar o comportarse distinto; para una validación seria, prioriza dispositivos reales Secure Biometric Authentication…
Si en un dispositivo real no aparece el botón biométrico, revisa:
- El usuario no tiene biometría configurada
- Falta un permiso en AndroidManifest
- Falta
NSFaceIDUsageDescriptionen iOS
Buenas prácticas de seguridad para producción
Si vas a llevar autenticación biométrica en Flutter a producción, estas son las decisiones que separan un “demo” de un producto serio.
No guardes secretos en storage normal
La biometría debe desbloquear secretos guardados en almacenamiento seguro (Keychain/Keystore). La autenticación biométrica en Flutter solo verifica identidad; el secreto lo guardas en una capa segura.
Ofrece fallback sin drama
Si la biometría falla o el usuario cancela, la app debe seguir funcionando con email/password o con el método principal que definas. La autenticación biométrica en Flutter es convenience, no bloqueo.
Textos claros en prompts
El localizedReason tiene que explicar el “para qué” de forma directa. Prompts confusos bajan la tasa de éxito del primer intento.
Usa biometría para operaciones sensibles
Además del login, la autenticación biométrica en Flutter encaja muy bien para confirmar acciones de alto riesgo: mostrar datos privados, exportar, borrar cuenta, cambiar método de pago.

Errores típicos y cómo evitarlos
- Mostrar el botón siempre
No lo hagas. La autenticación biométrica en Flutter debe mostrarse solo si el dispositivo es capaz y el usuario la ha configurado. - Confundir “capaz” con “habilitado”
Un móvil puede soportar biometría pero el usuario no la ha activado. Por eso separamosisDeviceCapableeisBiometricEnabled. - No contemplar cancelación
Cancelar no es “error”; es un resultado esperado. Trátalo como tal. - No testear en hardware real
Para validación real de autenticación biométrica en Flutter, el dispositivo físico manda.
Conclusión
Con este enfoque tienes una implementación sólida de autenticación biométrica en Flutter: permisos correctos en Android e iOS, helper reutilizable, UI que enseña el botón cuando toca y un flujo listo para crecer hacia un login real (desbloqueo de token, refresh de sesión y operaciones sensibles).
Si quieres llevar la autenticación biométrica en Flutter al siguiente nivel, el siguiente paso lógico es conectar este flujo con tu capa de sesión: guardar tokens en almacenamiento seguro y usar biometría como “unlock” al abrir la app o antes de acciones críticas.