One of the essential thing in mobile application is security especially if your building a finance app, and one of the most used security measure is using biometric authentication, which means you verify user by using phone face ID, Fingerprint or phone password.
Authentication using biometrics can be challenging. As it requires a good understanding of the underlying platform's APIs and implementation details.
But also, not all devices support biometric authentication, which requires developers to handle when user device does not have biometric authentication.
Luck us flutter provides a package for this local_auth
This package implements biometric security with Face ID and Touch ID/Fingerprint.
😜 Let's dive in and learn how to implement it in our flutter app.
But wait we need to go through the following steps to implement this.
- Setting up the project
- Checking biometric availability
- Requesting biometric authentication
- Handling authentication results
Setting up the project
First thing we need to install local authentication to our project.
dependencies:
local_auth: ^2.1.6
Then run the following command to install this plugin, though if your using vsCode you do not need to run this.
flutter packages get
Android Setup
Add following line under manifest tag in AndroidManifest.xml
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
Then Update the MainActivity.kt
file to use FlutterFragmentActivity
instead of FlutterActivity
:
//add this import
import io.flutter.embedding.android.FlutterFragmentActivity
//Chnage to FlutterFragmentActivity
class MainActivity: FlutterFragmentActivity() {
// ...
}
IOS Setup
Add following code to your info.plist
<key>NSFaceIDUsageDescription</key>
<string>Why is my app authenticating using face id?</string>
😮💨 we're done with the setup now let's write some code.
Checking biometric availability
We need to make sure that user phone has biometric authentication before we request to use it.
To check if biometric authentication is available or not. We use canCheckBiometrics
method on the LocalAuthentication
class.
Create a statefull
widget called LoginScreen
and add the following functions
import 'package:local_auth/local_auth.dart';
final LocalAuthentication _localAuth = LocalAuthentication();
//Check if biometric auth is available
Future<boolean> hasBiometrics() async {
try {
return await _localAuth.canCheckBiometrics;
} on PlatformException catch (e) {
return false;
}
}
//Check type of biometric auth available (Eg - Face ID, fingerprint)
Future<void> checkBiometricType() async {
final availableBiometrics = await _localAuth.getAvailableBiometrics();
print('Available biometrics: $availableBiometrics');
}
hasBiometrics
functions checks if user device has biometric authentication by using canCheckBiometrics
Authenticate user
If hasBiometrics function returns true now we can use biometric authentication to verify user.
Call the authenticate
method of the LocalAuthentication
class.
The authenticate method takes 3 parameters -
localizedReason - is the message to show to user while prompting them for authentication. This is typically along the lines of: 'Authenticate to access MyApp.'. This must not be empty.
authMessages - if you want to customize messages in the dialogs.
options - for configuring further authentication related options.
//Authenticate using biometric
Future<bool> authenticate() async {
final hasBiometric = await hasBiometrics();
if (hasBiometric) {
return await _localAuth.authenticate(
localizedReason: "Scan fingerprint to authenticate",
options: const AuthenticationOptions(
//Shows error dialog for system-related issues
useErrorDialogs: true,
//If true, auth dialog is show when app open from background
stickyAuth: true,
//Prevent non-biometric auth like such as pin, passcode.
biometricOnly: true,
),
);
} else {
return false;
}
}
Now let's build a simple UI for the authentication, we will have a login screen with a button and when a user is verified we will direct them to another page else we will display a snackbar of failure to authenticate.
Home screen
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Screen')),
body: const Center(
child: Text('Home Screen'),
),
);
}
}
And in our LoginScreen return the following
Scaffold(
appBar: AppBar(title: const Text('Login Screen')),
body: Center(
child: ElevatedButton(
onPressed: () async {
final isAuthenticated = await authenticate();
if (isAuthenticated) {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => HomeScreen()),
);
} else {
final snackBar = SnackBar(content: Text('Auth Failed'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
},
child: const Text('Authenticate'),
),
),
);
Now we are good to go, you can test this project in a real device to gain the experience.
Happy coding 🥳
Top comments (2)
Nice one, I've to try this very soon in my project!
Happy coding, we're waiting for your feedback 🥳