Secure Your App with Local Device Authentication

Published on by Flutter News Hub

Secure Your App with Local Device Authentication

The local_auth Flutter plugin empowers developers to incorporate robust local authentication mechanisms into their applications, leveraging on-device biometrics such as fingerprint and facial recognition.

Device Support and Biometric Capabilities

Before integrating local authentication, it's crucial to verify device compatibility. Utilize the canCheckBiometrics method to assess biometric hardware availability and isDeviceSupported() for general authentication support.

Supported biometric types include:

  • BiometricType.face
  • BiometricType.fingerprint
  • BiometricType.weak
  • BiometricType.strong

Enrolled Biometrics: A Prerequisite

canCheckBiometrics only indicates hardware support, not biometric enrollment. Determine enrolled biometrics using getAvailableBiometrics(). Note that device-specific and platform-specific types exist, so it's advisable to rely on general enrollment checks rather than specific biometric types.

Authentication Options and Customization

The authenticate() method defaults to biometric authentication but allows fallback to other authentication methods. To enforce biometric-only authentication, set the biometricOnly flag in the AuthenticationOptions:

import 'package:local_auth/local_auth.dart';

// ...

final bool didAuthenticate = await auth.authenticate(
  localizedReason: 'Please authenticate to show account balance',
  options: const AuthenticationOptions(biometricOnly: true),
);

Note: On Windows, biometricOnly is unsupported due to underlying API limitations.

Error Handling and Platform-Specific Dialogs

authenticate() throws PlatformExceptions in various error scenarios. Handle these exceptions as shown below:

import 'package:flutter/services.dart';
import 'package:local_auth/error_codes.dart' as auth_error;
import 'package:local_auth/local_auth.dart';

// ...

final LocalAuthentication auth = LocalAuthentication();

// ...

try {
  final bool didAuthenticate = await auth.authenticate(
    localizedReason: 'Please authenticate to show account balance',
    options: const AuthenticationOptions(useErrorDialogs: false),
  );

  // ...
} on PlatformException catch (e) {
  if (e.code == auth_error.notEnrolled) {
    // Handle no hardware case
  } else if (e.code == auth_error.lockedOut || e.code == auth_error.permanentlyLockedOut) {
    // ...
  } else {
    // ...
  }
}

The plugin provides default dialogs for scenarios where passcodes, PINs, or patterns are not set or biometrics are not enrolled. These can be customized using AuthMessages objects:

import 'package:local_auth/error_codes.dart' as auth_error;
import 'package:local_auth/local_auth.dart';

// ...

final LocalAuthentication auth = LocalAuthentication();

// ...

final bool didAuthenticate = await auth.authenticate(
  localizedReason: 'Please authenticate to show account balance',
  authMessages: const <AuthMessages>[
    AndroidAuthMessages(
      signInTitle: 'Oops! Biometric authentication required!',
      cancelButton: 'No thanks',
    ),
    IOSAuthMessages(
      cancelButton: 'No thanks',
    ),
  ],
);

Android and iOS Integration

Android

  • Ensure your activity inherits from FlutterFragmentActivity for correct functionality.
  • Declare the USE_BIOMETRIC permission in your AndroidManifest.xml file.
  • Set your LaunchTheme's parent to a valid Theme.AppCompat theme to avoid crashes on Android 8 and below.

iOS

  • Add the NSFaceIDUsageDescription key to your Info.plist file to enable Face ID. The value should explain why your app uses Face ID.

Sticky Authentication

Consider setting the stickyAuth option to true to prevent authentication failures when the app is put into the background due to interruptions (e.g., phone calls). In this scenario, the plugin will retry authentication when the app resumes.

Flutter News Hub