Building a Simple Biometric Authentication App in Flutter, Flutter Biometric Authentication, A Guide to implement fingerprint authentication in android using flutter.



Flutter Biometric Authenticaton 

Biometric authentication provides a seamless and secure way to authenticate users using fingerprint or facial recognition. In this blog, we will walk through the process of building a simple biometric authentication app in Flutter that integrates Shared Preferences to store login sessions and enable biometric login only after user authentication.

By the end of this tutorial, you will have a Flutter app where users can:
✅ Register/Login and store their login session in Shared Preferences.
✅ Enable biometric authentication only after logging in manually.
✅ Use fingerprint or face recognition to log in after enabling biometric login.

This blog is divided into two part the first part is logical implementation and second part is Ui Part. First copy paste code from 5️⃣Ui Part and then implement four steps shown in first part 



PART I


📂 Project Structure

📂 biometric_auth_app/

│── 📂 android/  

│── 📂 ios/      

│── 📂 lib/

│   │── 📂 screens/

│   │   │── home_screen.dart

│   │   │── login_screen.dart

│   │── main.dart

│   │── biometric_auth.dart

│── pubspec.yaml


📁 lib/screens/ (Screens Folder)

  • home_screen.dart → Displays a button to enable biometric authentication.
  • login_screen.dart → Normal login screen where users enter credentials manually.
  • signup_screen.dart → Allows users to sign up.

📁 lib/ (Root Directory)

  • main.dart → Entry point of the Flutter app.
  • biometric_auth.dart → Handles biometric authentication logic.


1️⃣Setting Up Dependencies

Run the following command in the terminal:


flutter pub add local_auth shared_preferences
  • local_auth → Used for fingerprint and face authentication.
  • shared_preferences → Used to store the user’s authentication status

2️⃣Configuring Android for Biometric Authentication

Since we are using local_auth, we need to make some changes in the Android project to support biometric authentication.

        a. Modify AndroidManifest.xml

                 📂 Path: android/app/src/main/AndroidManifest.xml
                  Open this file and add the following permissions inside the <manifest> tag:

            <uses-permission android:name="android.permission.USE_BIOMETRIC" />
            <uses-permission android:name="android.permission.USE_FINGERPRINT" />

         b.Modify MainActivity.kt

                 📂 Path:

          android/app/src/main/kotlin/com/example/biometric_auth_app/MainActivity.kt
                  By default, Flutter uses FlutterActivity, but biometric authentication requires                                  FlutterFragmentActivity.

                  Modify MainActivity.kt to extend FlutterFragmentActivity

            package com.example.biometric_auth_app
            import io.flutter.embedding.android.FlutterFragmentActivity             class MainActivity: FlutterFragmentActivity() {             }

                        Why this change?

      • FlutterActivity does not support biometric authentication dialogs properly.
      • FlutterFragmentActivity allows local_auth to work as expected.

 3️⃣Implement biometric authentication 


    //biometric_auth.dart

  import 'package:local_auth/local_auth.dart  ';
  import 'package:flutter/material.dart';
  import 'package:shared_preferences/shared_preferences.dart';

  class Biometricauth {
    final auth = LocalAuthentication();

    Future<void> checkBiometric(
        context, Widget successcreen, Widget failscreen, bool? issetup) async {
      bool canCheckBiometric = await auth.canCheckBiometrics;

      if (canCheckBiometric) {
        List<BiometricType> availableBiometric =
            await auth.getAvailableBiometrics();

        if (availableBiometric.isNotEmpty) {
          bool authenticated = await auth.authenticate(
            localizedReason: "Scan your finger to authenticate",
          );

          if (authenticated) {
            if (issetup == true) {
              final Future<SharedPreferences> prefs =
                  SharedPreferences.getInstance();
              prefs.then((SharedPreferences prefs) {
                prefs.setBool('isbiometricenabled', true);
              });
            }
            Navigator.push(
                context, MaterialPageRoute(builder: (context) => successcreen));
          } else {
            Navigator.push(
                context, MaterialPageRoute(builder: (context) => failscreen));
          }
        }
      }
    }
  }




4️⃣Implementing Shared Preferences for Login and Biometric

 How It Works?

  • When a user logs in, we store a flag (isLoggedIn = true) in Shared Preferences.
  • In the Home Screen, users can enable biometric authentication  (isbiometricenabled= true) in Shared Preferences. 
  • If biometric authentication is enabled and user has already logged in earlier, the Login Screen will allow login using a fingerprint.

a.  in init state of  login screen check shared prefs and decide weather to show biometric or not


 
  bool showbiometric = false;

    @override
    void initState() {
    super.initState();

    final Future<SharedPreferences> prefs = SharedPreferences.getInstance();

    prefs.then((SharedPreferences prefs) {

      bool isloggedin = prefs.getBool('isloggedin') ?? false;
      bool isbiometricenabled = prefs.getBool('isbiometricenabled') ?? false;

      if (isloggedin && isbiometricenabled) {
        setState(() { showbiometric = true; });
      } else {
        setState(() { showbiometric = false; });  
      }
    });

  }



b. add biometric authentication optino based on showbiometric bool value


  //Biometric option

  showbiometric
      ? GestureDetector(
          onTap: () => Biometricauth().checkBiometric(
              context, Homepage(), LoginScreen(),false),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Icon(
                Icons.fingerprint,
                color: Colors.white,
              ),
              const SizedBox(width: 10),
              const Text(
                'Tap to login with biometric',
                style: TextStyle(
                  color: Colors.white,
                ),
              ),
            ],
          ),
        )
      : Container(),


c. set isloggedin value to true on user login


  void _loginuser() async {

    final Future<SharedPreferences> prefs = SharedPreferences.getInstance();

    prefs.then((SharedPreferences prefs) {

      prefs.setBool('isloggedin', true);

      Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => Homepage(),
          ));

    });
  }


d. update logout button onpressed to clear all stored info in shared pref.


       //logout button

            ElevatedButton(
              onPressed: () async {
                final Future<SharedPreferences> prefs =
                    SharedPreferences.getInstance();
                prefs.then((SharedPreferences prefs) {
                  prefs.setBool('isloggedin', false);
                  prefs.setBool('isbiometricenabled', false);
                });
                Navigator.push(context,
                    MaterialPageRoute(builder: (context) => LoginScreen()));
              },
              child: Text('Logout'),
            ),


e. In homescreen call checkbiometric func with setup as true 


 
        //setup authentication button
            ElevatedButton(
              onPressed: () async {
                Biometricauth()
                    .checkBiometric(context, Homepage(), LoginScreen(), true);
              },
              child: Text('Setup Authentication'),
            ),


Above 6 steps contain the implementation of fingerprint biometric with shared preference.



PART II


5️⃣Ui Part



  //main.dart

  import 'package:biometric_auth_app/Screens/login_screen.dart';
  import 'package:flutter/material.dart';

  void main() => runApp(MyApp());

  class MyApp extends StatelessWidget {
    const MyApp({Key? key}) : super(key: key);

    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        debugShowCheckedModeBanner: false,
        title: "Fingerprint Auth",
        home: LoginScreen(),
      );
    }
  }


  //login_screen.dart

  import 'package:biometric_auth_app/Screens/home_screen.dart';
  import 'package:flutter/material.dart';

  class LoginScreen extends StatefulWidget {
    @override
    State<LoginScreen> createState() => _LoginScreenState();
  }

  class _LoginScreenState extends State<LoginScreen> {
    TextEditingController emailController = TextEditingController();
    TextEditingController passwordController = TextEditingController();

    void _loginuser() async {
      print("loginfunc called");
      // add your own logic of authentication here

      Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => Homepage(),
          ));
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SingleChildScrollView(
          child: Container(
            height: MediaQuery.of(context).size.height,
            decoration: BoxDecoration(
              gradient: LinearGradient(
                colors: [
                  Colors.black,
                  Colors.grey[900]!,
                ], // 👀 Apply dark gradient

                begin: Alignment.topLeft,
                end: Alignment.bottomRight,
              ),
            ),
            child: Column(
              children: [
                Expanded(
                  child: Container(
                    decoration: BoxDecoration(
                      borderRadius: const BorderRadius.only(
                        topLeft: Radius.circular(30),
                        topRight: Radius.circular(30),
                      ),
                      gradient: LinearGradient(
                        colors: [
                          Colors.black,
                          Colors.grey[900]!,
                        ] // 👀 Apply dark gradient
                        , // 👀 Keep white for light mode
                        begin: Alignment.topLeft,
                        end: Alignment.bottomRight,
                      ),
                    ),
                    child: Padding(
                      padding: const EdgeInsets.all(20),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.stretch,
                        children: [
                          const Text(
                            'Sign In',
                            style: TextStyle(
                              fontSize: 32,
                              fontWeight: FontWeight.bold,
                              color: Colors.white,
                            ),
                          ),
                          const SizedBox(height: 30),
                          TextField(
                            controller: emailController,
                            decoration: InputDecoration(
                              fillColor: Colors.white,
                              hintText: 'Email',
                              prefixIcon: const Icon(Icons.email),
                              border: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(10),
                              ),
                            ),
                          ),
                          const SizedBox(height: 20),
                          TextField(
                            controller: passwordController,
                            obscureText: true,
                            decoration: InputDecoration(
                              hintText: 'Password',
                              prefixIcon: const Icon(Icons.lock),
                              border: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(10),
                              ),
                            ),
                          ),
                          const SizedBox(height: 20),
                          Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: ElevatedButton(
                              onPressed: () async {
                                print("login button pressed");
                                _loginuser();
                              },
                              child: const Text('Sign In'),
                              style: ElevatedButton.styleFrom(
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(10),
                                ),
                                padding: const EdgeInsets.symmetric(vertical: 15),
                              ),
                            ),
                          ),
                          const SizedBox(height: 20),
                          Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: ElevatedButton(
                              onPressed: () {},
                              child: const Text('Sign Up'),
                              style: ElevatedButton.styleFrom(
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(10),
                                ),
                                padding: const EdgeInsets.symmetric(vertical: 15),
                              ),
                            ),
                          ),
                          const SizedBox(height: 20),

                          //Biometric option
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      );
    }
  }



  //home_screen.dart

  import 'package:biometric_auth_app/Screens/login_screen.dart';
  import 'package:flutter/material.dart';

  class Homepage extends StatefulWidget {
    const Homepage({super.key});

    @override
    State<Homepage> createState() => _HomepageState();
  }

  class _HomepageState extends State<Homepage> {
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('Welcome to the homepage'),

              // 👇 Add a button to navigate to the login screen
              ElevatedButton(
                onPressed: () {
                  Navigator.push(context,
                      MaterialPageRoute(builder: (context) => LoginScreen()));
                },
                child: Text('Login'),
              ),

              //logout button

              ElevatedButton(
                onPressed: () {
                  Navigator.push(context,
                      MaterialPageRoute(builder: (context) => LoginScreen()));
                },
                child: Text('Logout'),
              ),

              //setup authentication button
              ElevatedButton(
                onPressed: () {
                  // implement logic here
                },
                child: Text('Setup Authentication'),
              ),
            ],
          ),
        ),
      );
    }
  }




Post a Comment

Previous Post Next Post