This Flutter plugin provides means to perform local, on-device authentication of the user.
This means referring to biometric authentication on iOS (Touch ID or lock code) and the fingerprint APIs on Android (introduced in Android 6.0).
Import the relevant file:
import 'package:local_auth/local_auth.dart';
To check whether there is local authentication available on this device or not, call canCheckBiometrics:
bool canCheckBiometrics =
await localAuth.canCheckBiometrics;
Currently the following biometric types are implemented:
- BiometricType.face
- BiometricType.fingerprint
To get a list of enrolled biometrics, call getAvailableBiometrics:
List<BiometricType> availableBiometrics =
await auth.getAvailableBiometrics();
if (Platform.isIOS) {
if (availableBiometrics.contains(BiometricType.face)) {
// Face ID.
} else if (availableBiometrics.contains(BiometricType.fingerprint)) {
// Touch ID.
}
}
We have default dialogs with an 'OK' button to show authentication error messages for the following 2 cases:
- Passcode/PIN/Pattern Not Set. The user has not yet configured a passcode on iOS or PIN/pattern on Android.
- Touch ID/Fingerprint Not Enrolled. The user has not enrolled any fingerprints on the device.
Which means, if there's no fingerprint on the user's device, a dialog with instructions will pop up to let the user set up fingerprint. If the user clicks 'OK' button, it will return 'false'.
Use the exported APIs to trigger local authentication with default dialogs:
The authenticate()
method uses biometric authentication, but also allows
users to use pin, pattern, or passcode.
var localAuth = LocalAuthentication();
bool didAuthenticate =
await localAuth.authenticate(
localizedReason: 'Please authenticate to show account balance');
To authenticate using biometric authentication only, set biometricOnly
to true
.
var localAuth = LocalAuthentication();
bool didAuthenticate =
await localAuth.authenticate(
localizedReason: 'Please authenticate to show account balance',
biometricOnly: true);
If you don't want to use the default dialogs, call this API with 'useErrorDialogs = false'. In this case, it will throw the error message back and you need to handle them in your dart code:
bool didAuthenticate =
await localAuth.authenticate(
localizedReason: 'Please authenticate to show account balance',
useErrorDialogs: false);
You can use our default dialog messages, or you can use your own messages by passing in IOSAuthMessages and AndroidAuthMessages:
import 'package:local_auth/auth_strings.dart';
const iosStrings = const IOSAuthMessages(
cancelButton: 'cancel',
goToSettingsButton: 'settings',
goToSettingsDescription: 'Please set up your Touch ID.',
lockOut: 'Please reenable your Touch ID');
await localAuth.authenticate(
localizedReason: 'Please authenticate to show account balance',
useErrorDialogs: false,
iOSAuthStrings: iosStrings);
If needed, you can manually stop authentication for android:
void _cancelAuthentication() {
localAuth.stopAuthentication();
}
There are 6 types of exceptions: PasscodeNotSet, NotEnrolled, NotAvailable, OtherOperatingSystem, LockedOut and PermanentlyLockedOut. They are wrapped in LocalAuthenticationError class. You can catch the exception and handle them by different types. For example:
import 'package:flutter/services.dart';
import 'package:local_auth/error_codes.dart' as auth_error;
try {
bool didAuthenticate = await local_auth.authenticate(
localizedReason: 'Please authenticate to show account balance');
} on PlatformException catch (e) {
if (e.code == auth_error.notAvailable) {
// Handle this exception here.
}
}
Note that this plugin works with both TouchID and FaceID. However, to use the latter, you need to also add:
<key>NSFaceIDUsageDescription</key>
<string>Why is my app authenticating using face id?</string>
to your Info.plist file. Failure to do so results in a dialog that tells the user your app has not been updated to use TouchID.
Note that local_auth plugin requires the use of a FragmentActivity as
opposed to Activity. This can be easily done by switching to use
FlutterFragmentActivity
as opposed to FlutterActivity
in your
manifest (or your own Activity class if you are extending the base class).
Update your MainActivity.java:
import android.os.Bundle;
import io.flutter.app.FlutterFragmentActivity;
import io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin;
import io.flutter.plugins.localauth.LocalAuthPlugin;
public class MainActivity extends FlutterFragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FlutterAndroidLifecyclePlugin.registerWith(
registrarFor(
"io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin"));
LocalAuthPlugin.registerWith(registrarFor("io.flutter.plugins.localauth.LocalAuthPlugin"));
}
}
OR
Update your MainActivity.kt:
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterFragmentActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
}
}
Update your project's AndroidManifest.xml
file to include the
USE_FINGERPRINT
permissions:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<manifest>
On Android, you can check only for existence of fingerprint hardware prior
to API 29 (Android Q). Therefore, if you would like to support other biometrics
types (such as face scanning) and you want to support SDKs lower than Q,
do not call getAvailableBiometrics
. Simply call authenticate
with biometricOnly: true
.
This will return an error if there was no hardware available.
You can set the stickyAuth
option on the plugin to true so that plugin does not
return failure if the app is put to background by the system. This might happen
if the user receives a phone call before they get a chance to authenticate. With
stickyAuth
set to false, this would result in plugin returning failure result
to the Dart app. If set to true, the plugin will retry authenticating when the
app resumes.
For help getting started with Flutter, view our online documentation.
For help on editing plugin code, view the documentation.