With biometric authentication, we are able to verify users of our apps based on the biological characteristics of the users of our app. This can be done by checking if a user's fingerprint or face matches his/her fingerprint/face id in the phone. This method of authentication has gained popularity in the recent past especially with fintech apps that require a high level of security. They use it to verify that the user is indeed who they say they are. The uniqueness of our fingerprints and faces makes biometric authentication one of the most secure ways of verifying a user's identity.
We shall create a simple project with three screens, a login screen, a signup screen and a homepage.
The entire code for the project is available here
We shall use firebase for authentication and the Lottie package for some animations to spruce up our app. We shall then add these packages to our pubspec.yaml file at the root of our project folder.
dependencies:
flutter:
sdk: flutter
firebase_auth:
lottie:
Now onto the main subject of discussion which is biometric authentication. For this, we shall need to use the flutter_secure_storage package that shall enable us store the login details which in our case shall be an email and password securely. This package uses the AES encryption standard that ensures the security of our data.
Next up, the local_auth package. We shall use this to access the local on-device authentication mechanisms for our users. On Android, this is the fingerprint biometric authentication method while on IOS, this is the touch code, Face ID or lock code authentication mechanism. We shall then add these to our pubspec.yaml file.
dependencies:
flutter:
sdk: flutter
local_auth:
flutter_secure_storage:
Please note that for the local_auth package to work in IOS, we need to add a user defaults permission allowing the use of Face ID in our app. This shall be added in our info.plist file which is located in [project]/ios/Runner/info.plist
<key>NSFaceIDUsageDescription</key>
<string>Why is my app authenticating using face id?</string>
Additionally, for the package to work in android, we need to add this piece of code to our MainActivity.java page which is located in [project]/android/app/main/java/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"));
}
}
We also have to add the USE_FINGERPRINT and USE_BIOMETRIC permissions in our AndroidManifest.xml file which is located in [project]/android/app/src/main/AndroidManifest.xml
.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<manifest>
Additionally, we should set the minSdkVersion in[project]/android/app/build.gradle
to >= 18 so as to enable flutter_secure_storage to work
android {
...
defaultConfig {
...
minSdkVersion 18
...
}
}
Firstly, we shall create a new user in our app with firebase auth in our signup screen
class AuthService{
signUp(String email, String password, context) async {
try {
await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(e.message.toString())));
}
}
}
Next, we shall create our login page where the bulk of our biometric authentication logic shall be contained. We shall create localauth and storage variables that we shall use throughout the page.
final LocalAuthentication localAuth = LocalAuthentication();
final storage = const FlutterSecureStorage();
We should now go ahead and check if the device supports biometric authentication or not.
final canCheck = await localAuth.canCheckBiometrics;
final deviceIsSupported = await localAuth.isDeviceSupported();
Afterwards, we shall get the available biometrics on the device.
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 shall use a boolean flag bool _useTouchId = false;
that shall check whether the user has checked to use biometric authentication upon first login and if so, we shall write the values of the user's email and password to flutter_secure_storage for storage and later retrieval if we use biometric authentication.
final authenticated = await localAuth.authenticate(
localizedReason: 'Enable Face ID to sign in more easily',
useErrorDialogs: true,
stickyAuth: true);
if (authenticated) {
storage.write(key: 'email', value: email);
storage.write(key: 'password', value: password);
storage.write(key: 'usingBiometric', value: 'true');
}
In subsequent logins, if we intend to use biometric authentication, we shall go ahead and read the email and password values from flutter_secure_storage for authentication.
final authenticated = await localAuth.authenticate(
localizedReason: 'Enable Face ID to sign in more easily');
if (authenticated) {
String? userStoredEmail = await storage.read(
key: 'email',
);
String? userStoredPassword = await storage.read(
key: 'password',
);
AuthService()
.signIn(userStoredEmail!, userStoredPassword!, context);
}
And that's it !!! All that's remaining is for us to create a simple homescreen with a logout button.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'loginpage.dart';
class HomePage extends StatelessWidget {
HomePage({Key? key}) : super(key: key);
final _auth=FirebaseAuth.instance;
Color greenColor = const Color(0xFF00AF19);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Home screen',style: TextStyle(color: greenColor,fontWeight: FontWeight.w700,fontSize: 35),),
),
floatingActionButton: FloatingActionButton(
backgroundColor: greenColor,
onPressed: ()async {
await _auth.signOut();
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => LoginPage()));
},
child:const Icon(Icons.logout,),
),
);
}
}
And voila!!! Our app has a reliable and safe biometric authentication system.
Here is the project's source code and here is a video demo of the end result
Thanks for reading until the end (long read, I know)*. Stay tuned for more flutter tips in future
Top comments (0)