{"id":1477,"date":"2021-06-03T16:43:00","date_gmt":"2021-06-03T16:43:00","guid":{"rendered":"https:\/\/www.confianzit.com\/cit-blog\/?p=1477"},"modified":"2022-10-31T17:53:27","modified_gmt":"2022-10-31T17:53:27","slug":"biometric-authentication-with-flutter","status":"publish","type":"post","link":"https:\/\/www.confianzit.com\/cit-blog\/biometric-authentication-with-flutter\/","title":{"rendered":"Biometric Authentication with Flutter"},"content":{"rendered":"<p>[et_pb_section fb_built=&#8221;1&#8243; admin_label=&#8221;section&#8221; _builder_version=&#8221;4.9.4&#8243; custom_padding=&#8221;11px|||||&#8221; hover_enabled=&#8221;0&#8243; module_class=&#8221;blog-left-content&#8221; sticky_enabled=&#8221;0&#8243;][et_pb_row _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; column_structure=&#8221;2_3,1_3&#8243;][et_pb_column type=&#8221;2_3&#8243; _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>Flutter has many built-in widgets for building UI, including complex ones, but when it comes to using native features, we must either write native-level code or rely on third-party plugins. Thankfully, the Flutter community is highly active and most of the common use cases are developed by Flutter itself as add-on plugins. We will see how one such plugin, called local_auth, can be used to implement biometric authentication in Flutter.<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>As with all Flutter plugins, we begin by adding the local_auth plugin from pub.dev<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|2.5%|10%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"java\" style=\"font-family: monospace;\">flutter pub add local_auth<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>Since the plugin needs access to device specific features like fingerprint sensor data and camera (for facial recognition), we will have to add some settings in the native code, which is quite straightforward and explained well in the documentation. Specifically, the following changes would be required for iOS and Android:<\/p>\n<p><strong><b>For iOS:<\/b><\/strong>\u00a0<\/p>\n<p>\u00a0Add the NSFaceIDUsageDescription key with the appropriate reason as to why you would require in the Info.plist file as follows:<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|2.5%|10%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"xml\" style=\"font-family: monospace;\"><span style=\"color: #009900;\"><span style=\"color: #000000; font-weight: bold;\">&lt;key<span style=\"color: #000000; font-weight: bold;\">&gt;<\/span><\/span><\/span>NSFaceIDUsageDescription<span style=\"color: #009900;\"><span style=\"color: #000000; font-weight: bold;\">&lt;\/key<span style=\"color: #000000; font-weight: bold;\">&gt;<\/span><\/span><\/span>\n\u00a0\n<span style=\"color: #009900;\"><span style=\"color: #000000; font-weight: bold;\">&lt;string<span style=\"color: #000000; font-weight: bold;\">&gt;<\/span><\/span><\/span>Why is my app authenticating using face id?<span style=\"color: #009900;\"><span style=\"color: #000000; font-weight: bold;\">&lt;\/string<span style=\"color: #000000; font-weight: bold;\">&gt;<\/span><\/span><\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; custom_padding=&#8221;|||0px||&#8221;]<\/p>\n<p>Note that this is only required if you plan to use the Face ID feature of iOS, if not, you can simply skip this.<\/p>\n<p>\u00a0<strong><b>For Android:<\/b><\/strong><\/p>\n<p>\u00a0In Android you will have to add the permission to access fingerprint data in the AndroidManifest.xml file as follows:<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|2.5%|10%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"xml\" style=\"font-family: monospace;\"><span style=\"color: #009900;\"><span style=\"color: #000000; font-weight: bold;\">&lt;manifest<\/span> <span style=\"color: #000066;\">xmlns:android<\/span>=<span style=\"color: #ff0000;\">\"http:\/\/schemas.android.com\/apk\/res\/android\"<\/span> \n<span style=\"color: #000066;\">package<\/span>=<span style=\"color: #ff0000;\">\"com.example.app\"<\/span><span style=\"color: #000000; font-weight: bold;\">&gt;<\/span><\/span>\n\u00a0\u00a0<span style=\"color: #009900;\"><span style=\"color: #000000; font-weight: bold;\">&lt;uses-permission<\/span> <span style=\"color: #000066;\">android:name<\/span>=<span style=\"color: #ff0000;\">\"android.permission.USE_FINGERPRINT\"<\/span><span style=\"color: #000000; font-weight: bold;\">\/&gt;<\/span><\/span>\n<span style=\"color: #009900;\"><span style=\"color: #000000; font-weight: bold;\">&lt;manifest<span style=\"color: #000000; font-weight: bold;\">&gt;<\/span><\/span><\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>Apart from this you will need to add some code to the MainActivity.kt file in the Android source code as shown below:<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|2.5%|10%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"java\" style=\"font-family: monospace;\"><span style=\"color: #000000; font-weight: bold;\">import<\/span>\u00a0io.<span style=\"color: #006633;\">flutter<\/span>.<span style=\"color: #006633;\">embedding<\/span>.<span style=\"color: #006633;\">android<\/span>.<span style=\"color: #006633;\">FlutterFragmentActivity<\/span>\u00a0\n<span style=\"color: #000000; font-weight: bold;\">import<\/span>\u00a0io.<span style=\"color: #006633;\">flutter<\/span>.<span style=\"color: #006633;\">embedding<\/span>.<span style=\"color: #006633;\">engine<\/span>.<span style=\"color: #006633;\">FlutterEngine<\/span>\u00a0\n<span style=\"color: #000000; font-weight: bold;\">import<\/span>\u00a0io.<span style=\"color: #006633;\">flutter<\/span>.<span style=\"color: #006633;\">plugins<\/span>.<span style=\"color: #006633;\">GeneratedPluginRegistrant<\/span>\n\u00a0\u00a0\n<span style=\"color: #000000; font-weight: bold;\">class<\/span>\u00a0MainActivity<span style=\"color: #339933;\">:<\/span> FlutterFragmentActivity<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\u00a0\n\u00a0\u00a0\u00a0\u00a0override\u00a0fun\u00a0configureFlutterEngine<span style=\"color: #009900;\">(<\/span>flutterEngine<span style=\"color: #339933;\">:<\/span> FlutterEngine<span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0GeneratedPluginRegistrant.<span style=\"color: #006633;\">registerWith<\/span><span style=\"color: #009900;\">(<\/span>flutterEngine<span style=\"color: #009900;\">)<\/span>\u00a0\n\u00a0\u00a0\u00a0\u00a0<span style=\"color: #009900;\">}<\/span>\n<span style=\"color: #009900;\">}<\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; custom_padding=&#8221;|||0px||&#8221;]<\/p>\n<p>Now we can start building a simple app that will use biometrics to login a user with their biometric data.<\/p>\n<p>\u00a0We will start by creating a basic Flutter app using the Flutter create command and implement two screens.<\/p>\n<p>\u00a0The first one will be our home screen, which is basically a login page that simulates a login using a hardcoded email and password. We will also add another button to login using biometrics on the login screen.<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|2.5%|10%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"java\" style=\"font-family: monospace;\"><span style=\"color: #000000; font-weight: bold;\">import<\/span> <span style=\"color: #0000ff;\">'package:biometric_authentication\/success_page.dart'<\/span><span style=\"color: #339933;\">;<\/span>\n<span style=\"color: #000000; font-weight: bold;\">import<\/span> <span style=\"color: #0000ff;\">'package:flutter\/material.dart'<\/span><span style=\"color: #339933;\">;<\/span>\n<span style=\"color: #000000; font-weight: bold;\">import<\/span> <span style=\"color: #0000ff;\">'package:local_auth\/local_auth.dart'<\/span><span style=\"color: #339933;\">;<\/span>\n<span style=\"color: #000000; font-weight: bold;\">import<\/span> <span style=\"color: #0000ff;\">'package:shared_preferences\/shared_preferences.dart'<\/span><span style=\"color: #339933;\">;<\/span>\n\u00a0\n<span style=\"color: #000000; font-weight: bold;\">class<\/span> LoginPage <span style=\"color: #000000; font-weight: bold;\">extends<\/span> StatefulWidget <span style=\"color: #009900;\">{<\/span>\n  LoginPage<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n  @override\n  _LoginPageState createState<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #339933;\">=&gt;<\/span> _LoginPageState<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n<span style=\"color: #009900;\">}<\/span>\n\u00a0\n<span style=\"color: #000000; font-weight: bold;\">class<\/span> _LoginPageState <span style=\"color: #000000; font-weight: bold;\">extends<\/span> State <span style=\"color: #339933;\">&lt;<\/span> LoginPage <span style=\"color: #339933;\">&gt;<\/span> <span style=\"color: #009900;\">{<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">final<\/span> _emailController <span style=\"color: #339933;\">=<\/span> TextEditingController<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">final<\/span> _passwordController <span style=\"color: #339933;\">=<\/span> TextEditingController<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    bool isAuthenticating <span style=\"color: #339933;\">=<\/span> <span style=\"color: #000066; font-weight: bold;\">false<\/span><span style=\"color: #339933;\">;<\/span>\n    @override\n    Widget build<span style=\"color: #009900;\">(<\/span>BuildContext context<span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n      <span style=\"color: #000000; font-weight: bold;\">return<\/span> Scaffold<span style=\"color: #009900;\">(<\/span>\n          appBar<span style=\"color: #339933;\">:<\/span> AppBar<span style=\"color: #009900;\">(<\/span>\n            title<span style=\"color: #339933;\">:<\/span> Text<span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'Biometric Authentication'<\/span><span style=\"color: #009900;\">)<\/span>,\n          <span style=\"color: #009900;\">)<\/span>,\n\u00a0\n          body<span style=\"color: #339933;\">:<\/span> <span style=\"color: #003399;\">Stack<\/span><span style=\"color: #009900;\">(<\/span>\n            children<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">[<\/span>\n              Padding<span style=\"color: #009900;\">(<\/span>\n                padding<span style=\"color: #339933;\">:<\/span> EdgeInsets.<span style=\"color: #006633;\">all<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #cc66cc;\">16<\/span><span style=\"color: #009900;\">)<\/span>,\n                child<span style=\"color: #339933;\">:<\/span> Column<span style=\"color: #009900;\">(<\/span>\n                  mainAxisAlignment<span style=\"color: #339933;\">:<\/span> MainAxisAlignment.<span style=\"color: #006633;\">center<\/span>,\n                  children<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">[<\/span>\n                    <span style=\"color: #003399;\">TextField<\/span><span style=\"color: #009900;\">(<\/span>\n                      decoration<span style=\"color: #339933;\">:<\/span> InputDecoration<span style=\"color: #009900;\">(<\/span>labelText<span style=\"color: #339933;\">:<\/span> <span style=\"color: #0000ff;\">'Email'<\/span><span style=\"color: #009900;\">)<\/span>,\n                      controller<span style=\"color: #339933;\">:<\/span> _emailController,\n                    <span style=\"color: #009900;\">)<\/span>,\n\u00a0\n                    <span style=\"color: #003399;\">TextField<\/span><span style=\"color: #009900;\">(<\/span>\n                      obscureText<span style=\"color: #339933;\">:<\/span> <span style=\"color: #000066; font-weight: bold;\">true<\/span>,\n                      decoration<span style=\"color: #339933;\">:<\/span> InputDecoration<span style=\"color: #009900;\">(<\/span>labelText<span style=\"color: #339933;\">:<\/span> <span style=\"color: #0000ff;\">'Password'<\/span><span style=\"color: #009900;\">)<\/span>,\n                      controller<span style=\"color: #339933;\">:<\/span> _passwordController,\n                    <span style=\"color: #009900;\">)<\/span>,\n\u00a0\n                    SizedBox<span style=\"color: #009900;\">(<\/span>\n                      height<span style=\"color: #339933;\">:<\/span> MediaQuery.<span style=\"color: #006633;\">of<\/span><span style=\"color: #009900;\">(<\/span>context<span style=\"color: #009900;\">)<\/span>.<span style=\"color: #006633;\">size<\/span>.<span style=\"color: #006633;\">height<\/span> <span style=\"color: #339933;\">*<\/span> <span style=\"color: #cc66cc;\">0.1<\/span>,\n                    <span style=\"color: #009900;\">)<\/span>,\n\u00a0\n                    ElevatedButton<span style=\"color: #009900;\">(<\/span>\n                      child<span style=\"color: #339933;\">:<\/span> Text<span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'Submit'<\/span><span style=\"color: #009900;\">)<\/span>,\n                      onPressed<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> async <span style=\"color: #009900;\">{<\/span>\n                        <span style=\"color: #000000; font-weight: bold;\">final<\/span> result <span style=\"color: #339933;\">=<\/span> await logIn<span style=\"color: #009900;\">(<\/span>_emailController.<span style=\"color: #006633;\">value<\/span>.<span style=\"color: #006633;\">text<\/span>,\n                          _passwordController.<span style=\"color: #006633;\">value<\/span>.<span style=\"color: #006633;\">text<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n                        setState<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n                          isAuthenticating <span style=\"color: #339933;\">=<\/span> <span style=\"color: #000066; font-weight: bold;\">false<\/span><span style=\"color: #339933;\">;<\/span>\n                        <span style=\"color: #009900;\">}<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n\u00a0\n                        <span style=\"color: #000000; font-weight: bold;\">if<\/span> <span style=\"color: #009900;\">(<\/span>result<span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n                          Navigator.<span style=\"color: #006633;\">pushReplacement<\/span><span style=\"color: #009900;\">(<\/span>\n                            context,\n                            MaterialPageRoute<span style=\"color: #009900;\">(<\/span>builder<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">(<\/span>context<span style=\"color: #009900;\">)<\/span> <span style=\"color: #339933;\">=&gt;<\/span> SuccessPage<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span>,\n                          <span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n                        <span style=\"color: #009900;\">}<\/span> <span style=\"color: #000000; font-weight: bold;\">else<\/span> <span style=\"color: #009900;\">{<\/span>\n                          ScaffoldMessenger.<span style=\"color: #006633;\">of<\/span><span style=\"color: #009900;\">(<\/span>context<span style=\"color: #009900;\">)<\/span>.<span style=\"color: #006633;\">showSnackBar<\/span><span style=\"color: #009900;\">(<\/span>\n                            SnackBar<span style=\"color: #009900;\">(<\/span>content<span style=\"color: #339933;\">:<\/span> Text<span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'Invalid username\/password'<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n                        <span style=\"color: #009900;\">}<\/span>\n                      <span style=\"color: #009900;\">}<\/span>,\n                    <span style=\"color: #009900;\">)<\/span>,\n                    <span style=\"color: #000000; font-weight: bold;\">if<\/span> <span style=\"color: #009900;\">(<\/span>isAuthenticating<span style=\"color: #009900;\">)<\/span>\n                      <span style=\"color: #003399;\">Container<\/span><span style=\"color: #009900;\">(<\/span>\n                        color<span style=\"color: #339933;\">:<\/span> Colors.<span style=\"color: #006633;\">black<\/span>.<span style=\"color: #006633;\">withOpacity<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #cc66cc;\">0.5<\/span><span style=\"color: #009900;\">)<\/span>,\n                        child<span style=\"color: #339933;\">:<\/span> Center<span style=\"color: #009900;\">(<\/span>\n                          child<span style=\"color: #339933;\">:<\/span> CircularProgressIndicator<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span>,\n                        <span style=\"color: #009900;\">)<\/span>,\n                      <span style=\"color: #009900;\">)<\/span>\n                  <span style=\"color: #009900;\">]<\/span>,\n                <span style=\"color: #009900;\">)<\/span>,\n              <span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n            <span style=\"color: #009900;\">}<\/span>\n\u00a0\n            Future <span style=\"color: #339933;\">&lt;<\/span> bool <span style=\"color: #339933;\">&gt;<\/span> logIn<span style=\"color: #009900;\">(<\/span><span style=\"color: #003399;\">String<\/span> email, <span style=\"color: #003399;\">String<\/span> password<span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n              FocusScope.<span style=\"color: #006633;\">of<\/span><span style=\"color: #009900;\">(<\/span>context<span style=\"color: #009900;\">)<\/span>.<span style=\"color: #006633;\">unfocus<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n              setState<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n                isAuthenticating <span style=\"color: #339933;\">=<\/span> <span style=\"color: #000066; font-weight: bold;\">true<\/span><span style=\"color: #339933;\">;<\/span>\n              <span style=\"color: #009900;\">}<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n\u00a0\n              <span style=\"color: #000000; font-weight: bold;\">return<\/span> Future.<span style=\"color: #006633;\">delayed<\/span><span style=\"color: #009900;\">(<\/span>Duration<span style=\"color: #009900;\">(<\/span>seconds<span style=\"color: #339933;\">:<\/span> <span style=\"color: #cc66cc;\">2<\/span><span style=\"color: #009900;\">)<\/span>, <span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> async <span style=\"color: #009900;\">{<\/span>\n                <span style=\"color: #000000; font-weight: bold;\">if<\/span> <span style=\"color: #009900;\">(<\/span>email <span style=\"color: #339933;\">!=<\/span> <span style=\"color: #0000ff;\">'test@test.com'<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n                  <span style=\"color: #000000; font-weight: bold;\">return<\/span> <span style=\"color: #000066; font-weight: bold;\">false<\/span><span style=\"color: #339933;\">;<\/span>\n                <span style=\"color: #009900;\">}<\/span>\n\u00a0\n                <span style=\"color: #000000; font-weight: bold;\">if<\/span> <span style=\"color: #009900;\">(<\/span>password <span style=\"color: #339933;\">!=<\/span> <span style=\"color: #0000ff;\">\"password\"<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n                  <span style=\"color: #000000; font-weight: bold;\">return<\/span> <span style=\"color: #000066; font-weight: bold;\">false<\/span><span style=\"color: #339933;\">;<\/span>\n                <span style=\"color: #009900;\">}<\/span>\n\u00a0\n                <span style=\"color: #000000; font-weight: bold;\">final<\/span> sharedPreferences <span style=\"color: #339933;\">=<\/span> await SharedPreferences.<span style=\"color: #006633;\">getInstance<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n                sharedPreferences.<span style=\"color: #006633;\">setString<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'email'<\/span>, email<span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n                sharedPreferences.<span style=\"color: #006633;\">setString<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'password'<\/span>, password<span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n                <span style=\"color: #000000; font-weight: bold;\">return<\/span> <span style=\"color: #000066; font-weight: bold;\">true<\/span><span style=\"color: #339933;\">;<\/span>\n              <span style=\"color: #009900;\">}<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n            <span style=\"color: #009900;\">}<\/span>\n          <span style=\"color: #009900;\">}<\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>This should complete our initial screen. The second screen is just a success page where the user can logout.<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;2.5%|10%|2.5%|10%|true|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"java\" style=\"font-family: monospace;\"><span style=\"color: #000000; font-weight: bold;\">import<\/span> <span style=\"color: #0000ff;\">'package:biometric_authentication\/login_page.dart'<\/span><span style=\"color: #339933;\">;<\/span>\n<span style=\"color: #000000; font-weight: bold;\">import<\/span> <span style=\"color: #0000ff;\">'package:flutter\/material.dart'<\/span><span style=\"color: #339933;\">;<\/span>\n<span style=\"color: #000000; font-weight: bold;\">import<\/span> <span style=\"color: #0000ff;\">'package:shared_preferences\/shared_preferences.dart'<\/span><span style=\"color: #339933;\">;<\/span>\n\u00a0\n<span style=\"color: #000000; font-weight: bold;\">class<\/span> SuccessPage <span style=\"color: #000000; font-weight: bold;\">extends<\/span> StatelessWidget <span style=\"color: #009900;\">{<\/span>\n  @override\n  Widget build<span style=\"color: #009900;\">(<\/span>BuildContext context<span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">return<\/span> Scaffold<span style=\"color: #009900;\">(<\/span>\n      appBar<span style=\"color: #339933;\">:<\/span> AppBar<span style=\"color: #009900;\">(<\/span>title<span style=\"color: #339933;\">:<\/span> Text<span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'Success!'<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span>,\n      body<span style=\"color: #339933;\">:<\/span> Padding<span style=\"color: #009900;\">(<\/span>\n        padding<span style=\"color: #339933;\">:<\/span> EdgeInsets.<span style=\"color: #006633;\">all<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #cc66cc;\">16<\/span><span style=\"color: #009900;\">)<\/span>,\n        child<span style=\"color: #339933;\">:<\/span> Center<span style=\"color: #009900;\">(<\/span>\n          child<span style=\"color: #339933;\">:<\/span> Column<span style=\"color: #009900;\">(<\/span>\n            children<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">[<\/span>\n              Text<span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'Logged In!'<\/span><span style=\"color: #009900;\">)<\/span>,\n              ElevatedButton<span style=\"color: #009900;\">(<\/span>\n                child<span style=\"color: #339933;\">:<\/span> Text<span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'Log out'<\/span><span style=\"color: #009900;\">)<\/span>,\n                onPressed<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n                  Navigator.<span style=\"color: #006633;\">pushReplacement<\/span><span style=\"color: #009900;\">(<\/span>context,\n                    MaterialPageRoute<span style=\"color: #009900;\">(<\/span>builder<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">(<\/span>context<span style=\"color: #009900;\">)<\/span> <span style=\"color: #339933;\">=&gt;<\/span> LoginPage<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n                <span style=\"color: #009900;\">}<\/span>,\n              <span style=\"color: #009900;\">)<\/span>,\n            <span style=\"color: #009900;\">]<\/span>,\n          <span style=\"color: #009900;\">)<\/span>,\n        <span style=\"color: #009900;\">)<\/span>,\n      <span style=\"color: #009900;\">)<\/span>,\n    <span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n  <span style=\"color: #009900;\">}<\/span>\n<span style=\"color: #009900;\">}<\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>When the user logs in successfully they will be directed to a success screen and if not, we will show an error message using a snack bar. Note that in the login method we use the shared_preferences plugin also provided by the Flutter team to store the user\u2019s credentials. This will be used later to log in using biometrics. For real-world applications, we would not be doing this and would use something such as the user\u2019s token after authentication, but this will suffice for demonstration.<\/p>\n<p>\u00a0Basically, we wire up biometrics here in such a way that if the user logs in once manually, then they should be able to login using their biometrics the next time. We do this by retrieving the credentials of the user stored in the shared preferences and then use that to login if the biometric authentication is successful. This is where the local_auth plugin will come into play. We will first initialize an instance of the LocalAuthentication class provided by the plugin.<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|3%|10%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"java\" style=\"font-family: monospace;\"><span style=\"color: #000000; font-weight: bold;\">final<\/span> localAuth <span style=\"color: #339933;\">=<\/span> LocalAuthentication<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>Then we will use the plugin to authenticate the user\u2019s biometrics. Here we use the authenticate method available in the instance where we enforce the use of biometrics by setting the biometrics-only parameter to true and provide a reason as to why we need the user\u2019s biometrics.<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|3%|10%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"java\" style=\"font-family: monospace;\">localAuth.<span style=\"color: #006633;\">authenticate<\/span><span style=\"color: #009900;\">(<\/span>\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0localizedReason<span style=\"color: #339933;\">:<\/span> <span style=\"color: #0000ff;\">'Please verify to login without credentials'<\/span>,\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0biometricOnly<span style=\"color: #339933;\">:<\/span> <span style=\"color: #000066; font-weight: bold;\">true<\/span>,\u00a0\n\u00a0\u00a0\u00a0 <span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>This would be the baseline implementation for using biometrics in the app. Now we just need to write a function where we use this logic to authenticate the user with biometrics and then use the stored credentials to login to the application. This can be done as shown below:<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|3%|6.5%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"java\" style=\"font-family: monospace;\">Future <span style=\"color: #339933;\">&lt;<\/span> bool <span style=\"color: #339933;\">&gt;<\/span> loginWithBiometrics<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> async <span style=\"color: #009900;\">{<\/span>\n  setState<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n    isAuthenticating <span style=\"color: #339933;\">=<\/span> <span style=\"color: #000066; font-weight: bold;\">true<\/span><span style=\"color: #339933;\">;<\/span>\n  <span style=\"color: #009900;\">}<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n  <span style=\"color: #000000; font-weight: bold;\">final<\/span> result <span style=\"color: #339933;\">=<\/span> await localAuth.<span style=\"color: #006633;\">authenticate<\/span><span style=\"color: #009900;\">(<\/span>localizedReason<span style=\"color: #339933;\">:<\/span> <span style=\"color: #0000ff;\">'Please verify to login without credentials'<\/span>, biometricOnly<span style=\"color: #339933;\">:<\/span> <span style=\"color: #000066; font-weight: bold;\">true<\/span>, <span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n  <span style=\"color: #000000; font-weight: bold;\">if<\/span> <span style=\"color: #009900;\">(<\/span>result<span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">final<\/span> sharedPreferences <span style=\"color: #339933;\">=<\/span> await SharedPreferences.<span style=\"color: #006633;\">getInstance<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">final<\/span> email <span style=\"color: #339933;\">=<\/span> sharedPreferences.<span style=\"color: #006633;\">getString<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'email'<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">final<\/span> password <span style=\"color: #339933;\">=<\/span> sharedPreferences.<span style=\"color: #006633;\">getString<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'password'<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">if<\/span> <span style=\"color: #009900;\">(<\/span>email <span style=\"color: #339933;\">==<\/span> <span style=\"color: #000066; font-weight: bold;\">null<\/span> <span style=\"color: #339933;\">||<\/span> password <span style=\"color: #339933;\">==<\/span> <span style=\"color: #000066; font-weight: bold;\">null<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n      <span style=\"color: #000000; font-weight: bold;\">return<\/span> <span style=\"color: #000066; font-weight: bold;\">false<\/span><span style=\"color: #339933;\">;<\/span>\n    <span style=\"color: #009900;\">}<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">return<\/span> logIn<span style=\"color: #009900;\">(<\/span>email, password<span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n  <span style=\"color: #009900;\">}<\/span>\n  <span style=\"color: #000000; font-weight: bold;\">return<\/span> <span style=\"color: #000066; font-weight: bold;\">false<\/span><span style=\"color: #339933;\">;<\/span>\n<span style=\"color: #009900;\">}<\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>We will now use this function by creating another button on the page to login using biometrics.<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|3%|10%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"java\" style=\"font-family: monospace;\">ElevatedButton<span style=\"color: #009900;\">(<\/span>\n  child<span style=\"color: #339933;\">:<\/span> Text<span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'Login with biometrics'<\/span><span style=\"color: #009900;\">)<\/span>,\n  onPressed<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> async <span style=\"color: #009900;\">{<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">final<\/span> result <span style=\"color: #339933;\">=<\/span> await loginWithBiometrics<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    setState<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n      isAuthenticating <span style=\"color: #339933;\">=<\/span> <span style=\"color: #000066; font-weight: bold;\">false<\/span><span style=\"color: #339933;\">;<\/span>\n    <span style=\"color: #009900;\">}<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n\u00a0\n    <span style=\"color: #000000; font-weight: bold;\">if<\/span> <span style=\"color: #009900;\">(<\/span>result<span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span>\n      Navigator.<span style=\"color: #006633;\">pushReplacement<\/span><span style=\"color: #009900;\">(<\/span>\n        context,\n        MaterialPageRoute<span style=\"color: #009900;\">(<\/span>builder<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">(<\/span>context<span style=\"color: #009900;\">)<\/span> <span style=\"color: #339933;\">=&gt;<\/span> SuccessPage<span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span>,\n      <span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    <span style=\"color: #009900;\">}<\/span> <span style=\"color: #000000; font-weight: bold;\">else<\/span> <span style=\"color: #009900;\">{<\/span>\n      ScaffoldMessenger.<span style=\"color: #006633;\">of<\/span><span style=\"color: #009900;\">(<\/span>context<span style=\"color: #009900;\">)<\/span>.<span style=\"color: #006633;\">showSnackBar<\/span><span style=\"color: #009900;\">(<\/span>SnackBar<span style=\"color: #009900;\">(<\/span>\n        content<span style=\"color: #339933;\">:<\/span> Text<span style=\"color: #009900;\">(<\/span>\n          <span style=\"color: #0000ff;\">'Failed to login with biometrics. Please login manually.'<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    <span style=\"color: #009900;\">}<\/span>\n  <span style=\"color: #009900;\">}<\/span>,\n<span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>This should work for our basic application. But what if there are no credentials stored in the first place? Then what would the button do? Ideally, we would be showing the button only if there are any credentials stored, which can be done during build or with a FutureBuilder. For now, we just show a generic message prompting the user to login manually.<\/p>\n<p>Additionally, we could add another button on our success screen to reset the credentials which would remove the stored local credentials to simulate the credentials being removed or the token being expired.<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; text_text_color=&#8221;#000000&#8243; background_color=&#8221;#eff0f1&#8243; custom_margin=&#8221;|||60px|false|false&#8221; custom_padding=&#8221;3%|10%|3%|10%|false|false&#8221; border_width_top=&#8221;10px&#8221; border_color_top=&#8221;#2ea3f2&#8243;]<\/p>\n<pre class=\"java\" style=\"font-family: monospace;\">ElevatedButton<span style=\"color: #009900;\">(<\/span>\n  child<span style=\"color: #339933;\">:<\/span> Text<span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'Reset local credentials'<\/span><span style=\"color: #009900;\">)<\/span>,\n  style<span style=\"color: #339933;\">:<\/span> ElevatedButton.<span style=\"color: #006633;\">styleFrom<\/span><span style=\"color: #009900;\">(<\/span>\n    primary<span style=\"color: #339933;\">:<\/span> Colors.<span style=\"color: #006633;\">red<\/span>,\n  <span style=\"color: #009900;\">)<\/span>,\n\u00a0\n  onPressed<span style=\"color: #339933;\">:<\/span> <span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span> async <span style=\"color: #009900;\">{<\/span>\n    <span style=\"color: #000000; font-weight: bold;\">final<\/span> sharedPreferences <span style=\"color: #339933;\">=<\/span> await SharedPreferences.<span style=\"color: #006633;\">getInstance<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    sharedPreferences.<span style=\"color: #006633;\">remove<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'email'<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    sharedPreferences.<span style=\"color: #006633;\">remove<\/span><span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'password'<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n    ScaffoldMessenger.<span style=\"color: #006633;\">of<\/span><span style=\"color: #009900;\">(<\/span>context<span style=\"color: #009900;\">)<\/span>\n      .<span style=\"color: #006633;\">showSnackBar<\/span><span style=\"color: #009900;\">(<\/span>SnackBar<span style=\"color: #009900;\">(<\/span>content<span style=\"color: #339933;\">:<\/span> Text<span style=\"color: #009900;\">(<\/span><span style=\"color: #0000ff;\">'Credentials Reset'<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span>\n  <span style=\"color: #009900;\">}<\/span>,\n<span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span><\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p>This should wrap up our demo application. Our final app should look like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/Picture1.png\" width=\"305\" height=\"542\" alt=\"\" class=\"wp-image-1523 alignnone size-full\" style=\"display: block; margin-left: auto; margin-right: auto;\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;]<\/p>\n<p><strong><b>Conclusion<\/b><\/strong><\/p>\n<p>We have seen how we can interact with device level features such as fingerprint or face id for biometric authentication using plugins available in Flutter. Apart from that you can also see how you could use the same to integrate with your authentication flow.<\/p>\n<p>\u00a0For real world applications however, it would be better not to store your credentials on the device and rather use something like the authentication token from your authentication service or use something a bit more secure for storing instead of shared_preferences, such as the flutter_secure_storage plugin which exposes the encrypted storage of Android (KeyStore) and iOS (KeyChain).<\/p>\n<p>[\/et_pb_text][\/et_pb_column][et_pb_column type=&#8221;1_3&#8243; _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221;][et_pb_code _builder_version=&#8221;4.9.4&#8243; _module_preset=&#8221;default&#8221; locked=&#8221;off&#8221;]<\/p>\n<div class=\"blog-floating-form\"><!-- [et_pb_line_break_holder] -->  <\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_62 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title \" >Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.confianzit.com\/cit-blog\/biometric-authentication-with-flutter\/#Talk_to_our_experts_now\" title=\"    Talk to our experts now  \">    Talk to our experts now  <\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.confianzit.com\/cit-blog\/biometric-authentication-with-flutter\/#Talk_To_Our_Experts_Now\" title=\"Talk To Our Experts Now\n\t\">Talk To Our Experts Now\n\t<\/a><\/li><\/ul><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n<h1><span class=\"ez-toc-section\" id=\"Talk_to_our_experts_now\"><\/span><!-- [et_pb_line_break_holder] -->    Talk to our experts now<!-- [et_pb_line_break_holder] -->  <span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p><!-- [et_pb_line_break_holder] -->  \n<div class=\"wpcf7 no-js\" id=\"wpcf7-f1888-o1\" lang=\"en-US\" dir=\"ltr\">\n<div class=\"screen-reader-response\"><p role=\"status\" aria-live=\"polite\" aria-atomic=\"true\"><\/p> <ul><\/ul><\/div>\n<form action=\"\/cit-blog\/wp-json\/wp\/v2\/posts\/1477#wpcf7-f1888-o1\" method=\"post\" class=\"wpcf7-form init\" aria-label=\"Contact form\" novalidate=\"novalidate\" data-status=\"init\">\n<div style=\"display: none;\">\n<input type=\"hidden\" name=\"_wpcf7\" value=\"1888\" \/>\n<input type=\"hidden\" name=\"_wpcf7_version\" value=\"5.8.6\" \/>\n<input type=\"hidden\" name=\"_wpcf7_locale\" value=\"en_US\" \/>\n<input type=\"hidden\" name=\"_wpcf7_unit_tag\" value=\"wpcf7-f1888-o1\" \/>\n<input type=\"hidden\" name=\"_wpcf7_container_post\" value=\"0\" \/>\n<input type=\"hidden\" name=\"_wpcf7_posted_data_hash\" value=\"\" \/>\n<input type=\"hidden\" name=\"_wpcf7_recaptcha_response\" value=\"\" \/>\n<\/div>\n<div class=\"form-block\" style=\"    background: #fff;\">\n\t<h3 style=\"    background: #0C2464;\n    border-bottom: 5px solid #cecece;\n    border-radius: 5px 5px 90px 90px;\n    margin: 0 auto;\n    text-align: center;\n    padding: 20px;\n    color: #fff;    margin-bottom: 15px;\"><span class=\"ez-toc-section\" id=\"Talk_To_Our_Experts_Now\"><\/span><b>Talk To Our Experts Now<\/b>\n\t<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\t<div style=\"padding:20px;\">\n\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"your-name\"><input size=\"40\" class=\"wpcf7-form-control wpcf7-text wpcf7-validates-as-required your-name\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Name\" value=\"\" type=\"text\" name=\"your-name\" \/><\/span>\n\t\t<\/p>\n\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"your-email\"><input size=\"40\" class=\"wpcf7-form-control wpcf7-email wpcf7-validates-as-required wpcf7-text wpcf7-validates-as-email your-email\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Email\" value=\"\" type=\"email\" name=\"your-email\" \/><\/span>\n\t\t<\/p>\n\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"your-number\"><input size=\"40\" class=\"wpcf7-form-control wpcf7-tel wpcf7-validates-as-required wpcf7-text wpcf7-validates-as-tel your-number\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Phone Number\" value=\"\" type=\"tel\" name=\"your-number\" \/><\/span>\n\t\t<\/p>\n\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"message\"><textarea cols=\"40\" rows=\"10\" class=\"wpcf7-form-control wpcf7-textarea wpcf7-validates-as-required form-message\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Message\" name=\"message\"><\/textarea><\/span>\n\t\t<\/p>\n\t<span class=\"wpcf7-form-control-wrap recaptcha\" data-name=\"recaptcha\"><span data-sitekey=\"6LfFkQATAAAAAIYlZ_UH9UozO-OLkpAaWPWx6QtM\" class=\"wpcf7-form-control wpcf7-recaptcha g-recaptcha\"><\/span>\r\n<noscript>\r\n\t<div class=\"grecaptcha-noscript\">\r\n\t\t<iframe loading=\"lazy\" src=\"https:\/\/www.google.com\/recaptcha\/api\/fallback?k=6LfFkQATAAAAAIYlZ_UH9UozO-OLkpAaWPWx6QtM\" frameborder=\"0\" scrolling=\"no\" width=\"310\" height=\"430\">\r\n\t\t<\/iframe>\r\n\t\t<textarea name=\"g-recaptcha-response\" rows=\"3\" cols=\"40\" placeholder=\"reCaptcha Response Here\">\r\n\t\t<\/textarea>\r\n\t<\/div>\r\n<\/noscript>\r\n<\/span>\n\t\t<div class=\"form-buttons\">\n\t\t\t<p><input class=\"wpcf7-form-control wpcf7-submit has-spinner\" type=\"submit\" value=\"Get a free quote\" \/>\n\t\t\t<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div><div class=\"wpcf7-response-output\" aria-hidden=\"true\"><\/div>\n<\/form>\n<\/div>\n<!-- [et_pb_line_break_holder] --><\/div>\n<p>[\/et_pb_code][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Flutter has many built-in widgets for building UI, including complex ones, but when it comes to using native features, we must either write native-level code or rely on third-party plugins. Thankfully, the Flutter community is highly active and most of the common use cases are developed by Flutter itself as add-on plugins. We will see [&hellip;]<\/p>\n","protected":false},"author":11,"featured_media":1534,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"<!-- wp:paragraph -->\n<p>Flutter has many built-in widgets for building UI, including complex ones, but when it comes to using native features, we must either write native-level code or rely on third-party plugins. Thankfully, the Flutter community is highly active and most of the common use cases are developed by <a href=\"https:\/\/www.confianzit.com\/cit-blog\/flutter-paginated-lazy-loading-listview\/\" class=\"rank-math-link\">Flutter<\/a> itself as add-on plugins. We will see how one such plugin, called local_auth, can be used to implement biometric authentication in Flutter.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>As with all Flutter plugins, we begin by adding the local_auth plugin from pub.dev<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1479,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-001.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-001.png\" alt=\"\" class=\"wp-image-1479\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>Since the plugin needs access to device specific features like fingerprint sensor data and camera (for facial recognition), we will have to add some settings in the native code, which is quite straightforward and explained well in the documentation. Specifically, the following changes would be required for <a href=\"https:\/\/www.confianzit.com\/mobile-app-development\" class=\"rank-math-link\">iOS and Android<\/a>:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p><strong>For iOS:<\/strong>&nbsp;<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Add the <img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-012-1.png\"> key with the appropriate reason as to why you would require in the Info.plist file as follows:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1480,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-002.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-002.png\" alt=\"\" class=\"wp-image-1480\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>Note that this is only required if you plan to use the Face ID feature of iOS, if not, you can simply skip this.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p><strong>For Android:<\/strong><\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>In Android you will have to add the permission to access fingerprint data in the AndroidManifest.xml file as follows:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1481,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-003.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-003.png\" alt=\"\" class=\"wp-image-1481\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>Apart from this you will need to add some code to the MainActivity.kt file in the Android source code as shown below:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1482,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-004.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-004.png\" alt=\"\" class=\"wp-image-1482\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>Now we can start building a simple app that will use biometrics to login a user with their biometric data.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>We will start by creating a basic Flutter app using the Flutter create command and implement two screens.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:html -->\n<img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-005.png\">\n<!-- \/wp:html -->\n\n<!-- wp:paragraph -->\n<p>The first one will be our home screen, which is basically a login page that simulates a login using a hardcoded email and password. We will also add another button to login using biometrics on the login screen.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>This should complete our initial screen. The second screen is just a success page where the user can logout.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1490,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-006.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-006.png\" alt=\"\" class=\"wp-image-1490\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>When the user logs in successfully they will be directed to a success screen and if not, we will show an error message using a snackbar. Note that in the login method we use the shared_preferences plugin also provided by the Flutter team to store the user\u2019s credentials. This will be used later to log in using biometrics. For real world applications we would not be doing this and would use something such as the user\u2019s token after authentication, but this will suffice for demonstration.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1492,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-007.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-007.png\" alt=\"\" class=\"wp-image-1492\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>Basically we wire up biometrics here in such a way that if the user logs in once manually, then they should be able to login using their biometrics the next time. We do this by retrieving the credentials of the user stored in the shared preferences and then use that to login if the biometric authentication is successful. This is where the local_auth plugin will come into play. We will first initialize an instance of the LocalAuthentication class provided by the plugin.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Then we will use the plugin to authenticate the user\u2019s biometrics. Here we use the authenticate method available in the instance where we enforce the use of biometrics by setting the biometrics-only parameter to true and provide a reason as to why we need the user\u2019s biometrics.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1493,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-008.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-008.png\" alt=\"\" class=\"wp-image-1493\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>This would be the baseline implementation for using biometrics in the app. Now we just need to write a function where we use this logic to authenticate the user with biometrics and then use the stored credentials to login to the application. This can be done as shown below:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1494,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-009.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-009.png\" alt=\"\" class=\"wp-image-1494\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>We will now use this function by creating another button on the page to login using biometrics.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1495,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-010.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-010.png\" alt=\"\" class=\"wp-image-1495\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>This should work for our basic application. But what if there are no credentials stored in the first place? Then what would the button do? Ideally, we would be showing the button only if there are any credentials stored, which can be done during build or with a FutureBuilder. For now, we just show a generic message prompting the user to login manually.&nbsp;<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Additionally, we could add another button on our success screen to reset the credentials which would remove the stored local credentials to simulate the credentials being removed or the token being expired.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"id\":1496,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-011.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-011.png\" alt=\"\" class=\"wp-image-1496\" \/><\/a><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>This should wrap up our demo application. Our final app should look like this:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:image {\"align\":\"center\",\"id\":1501,\"sizeSlug\":\"large\",\"linkDestination\":\"media\"} -->\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-013.png\"><img src=\"https:\/\/www.confianzit.com\/cit-blog\/wp-content\/uploads\/2021\/06\/flutter-013.png\" alt=\"\" class=\"wp-image-1501\" \/><\/a><\/figure><\/div>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p><strong>Conclusion<\/strong><\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>We have seen how we can interact with device level features such as fingerprint or face id for biometric authentication using plugins available in Flutter. Apart from that you can also see how you could use the same to integrate with your authentication flow.&nbsp;<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>For real world applications however, it would be better not to store your credentials on the device and rather use something like the authentication token from your authentication service or use something a bit more secure for storing instead of shared_preferences, such as the flutter_secure_storage plugin which exposes the encrypted storage of <a href=\"https:\/\/www.confianzit.com\/android-application-development\" class=\"rank-math-link\">Android<\/a> (KeyStore) and <a href=\"https:\/\/www.confianzit.com\/ios-application-development\" class=\"rank-math-link\">iOS<\/a> (KeyChain).<\/p>\n<!-- \/wp:paragraph -->","_et_gb_content_width":"","footnotes":""},"categories":[79,80,5,78,7,8],"tags":[161,93,23,183],"_links":{"self":[{"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/posts\/1477"}],"collection":[{"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/comments?post=1477"}],"version-history":[{"count":15,"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/posts\/1477\/revisions"}],"predecessor-version":[{"id":1977,"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/posts\/1477\/revisions\/1977"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/media\/1534"}],"wp:attachment":[{"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/media?parent=1477"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/categories?post=1477"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.confianzit.com\/cit-blog\/wp-json\/wp\/v2\/tags?post=1477"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}