How to use fingerprint authentication in cordova (phonegap,ionic) for Android and iOS

How to use fingerprint authentication in cordova (phonegap,ionic) for Android and iOS

Typing a password into your smartphone is, like, so 2013-2014. With support for fingerprint sensors becoming a native part of Android in Marshmallow, Touch ID in Apple, and fingerprint sensors rapidly becoming standard fare in flagship phones as a result t's easy to get spoiled by the ease of unlocking something with a touch of your finger.

We cannot forget to use this feature if is available on the device in our cordova application and your app offers a way to use it. Just imagine, instant login, instant payment etc.

To use the fingerprint authentication on our device using cordova, we are going to use 2 plugins (respectively for every know platform : Android and iOS).

Requirements

  • A device (iPhone >= 5s for Apple and An Android Device with fingerprint) with fingerprint reader support.

Note that in every platform there's a way to detect if the fingerprint is supported or not to keep providing support to older devices.

It's worth to say, that if you want to implement this feature at the initialization of your cordova app (i.e to access the application, you need to grant the access with the fingerprint) you need to execute the code during or after the ondeviceready event of the document:

document.addEventListener("deviceready", function(){
    // Here the code to verificate the fingerprint
}, false);

Now that you know the basics, let's get started!

Android

For the Android platform, you need to use the cordova-plugin-android-fingerprint-auth.

This plugin was created referencing the Fingerprint Dialog sample and the Confirm Credential sample referenced by the Android 6.0 APIs webpage.

This plugin will open a native dialog fragment prompting the user to authenticate using their fingerprint. If the device has a secure lockscreen (pattern, PIN, or password), the user may opt to authenticate using that method as a backup.

To install this plugin on your project execute the following command in the command prompt :

cordova plugin add cordova-plugin-android-fingerprint-auth
REM Or clone the repository
cordova plugin add https://github.com/mjwheatley/cordova-plugin-android-fingerprint-auth.git

After a succesfully installation, a Global variable will be accesible in the document named FingerprintAuth. This object has 4 available methods :

The logic to make it work is simple, check if the device has fingerprint recognition, in case it does and it has registered fingerprints then use the encrypt method to show the dialog that verifies the fingerprint and encrypt some data inside that you can decrypt later using the decrypt method.

If you're looking to authenticate something with the fingerprint device, then you're looking for the encrypt method. This method expects an object with its configuration, the available properties are listed in the following table :

Param Type Default Description
clientId String undefined (REQUIRED) Used as the alias for your app's secret key in the Android Key Store. Also used as part of the Shared Preferences key for the cipher userd to encrypt the user credentials.
username String undefined Used to create credential string for encrypted token and as alias to retrieve the cipher.
password String undefined Used to create credential string for encrypted token
token String undefined Data to be decrypted. Required for decrypt().
disableBackup boolean false Set to true to remove the "USE BACKUP" button
maxAttempts number 5 The device max is 5 attempts. Set this parameter if you want to allow fewer than 5 attempts.
locale String "en_US" Change the language displayed on the authentication dialog.
  • English: "en_US"
  • Italian: "it"
  • Spanish: "es"
  • Russian: "ru"
  • French: "fr"
  • Chinese (Simplified):
    • "zh_CN"
    • "zh_SG"
  • Chinese (Traditional):
    • "zh"
    • "zh_HK"
    • "zh_TW"
    • "zh_MO"
  • Norwegian: "no"
  • Portuguese: "pt"
  • Japanese: "ja"
  • German: "de"
userAuthRequired boolean true Require the user to authenticate with a fingerprint to authorize every use of the key. New fingerprint enrollment will invalidate key and require backup authenticate to re-enable the fingerprint authentication dialog.
dialogTitle String undefined Set the title of the fingerprint authentication dialog.
dialogMessage String undefined Set the message of the fingerprint authentication dialog.
dialogHint String undefined Set the hint displayed by the fingerprint icon on the fingerprint authentication dialog.

The following snippet shows a very basic implementation and handles the fingerprint authentication with all its possible cases (if there's a device that checks fingerprint and there are registered fingerprints):

Note

The following snippet works with the latest version. We encourage anyway to check the documentation of the plugin for possible changes or to understand more about how the plugin works. Besides, as you can see there are a lot of callbacks, to make your code more organized we recommend you to implement it using Javascript Promises.

// Check if device supports fingerprint
/**
* @return {
*      isAvailable:boolean,
*      isHardwareDetected:boolean,
*      hasEnrolledFingerprints:boolean
*   }
*/
FingerprintAuth.isAvailable(function (result) {

    console.log("FingerprintAuth available: " + JSON.stringify(result));
    
    // If has fingerprint device and has fingerprints registered
    if (result.isAvailable == true && result.hasEnrolledFingerprints == true) {

        // Check the docs to know more about the encryptConfig object :)
        var encryptConfig = {
            clientId: "myAppName",
            username: "currentUser",
            password: "currentUserPassword",
            maxAttempts: 5,
            locale: "en_US",
            dialogTitle: "Hey dude, your finger",
            dialogMessage: "Put your finger on the device",
            dialogHint: "No one will steal your identity, promised"
        }; // See config object for required parameters

        // Set config and success callback
        FingerprintAuth.encrypt(encryptConfig, function(_fingerResult){
            console.log("successCallback(): " + JSON.stringify(_fingerResult));
            if (_fingerResult.withFingerprint) {
                console.log("Successfully encrypted credentials.");
                console.log("Encrypted credentials: " + result.token);  
            } else if (_fingerResult.withBackup) {
                console.log("Authenticated with backup password");
            }
        // Error callback
        }, function(err){
                if (err === "Cancelled") {
                console.log("FingerprintAuth Dialog Cancelled!");
            } else {
                console.log("FingerprintAuth Error: " + err);
            }
        });
    }

/**
* @return {
*      isAvailable:boolean,
*      isHardwareDetected:boolean,
*      hasEnrolledFingerprints:boolean
*   }
*/
}, function (message) {
    console.log("isAvailableError(): " + message);
});

The Dialog will be shown after the execution of the encrypt method. Simple and quick authentication without use any password.

Fingerprint Auth Dialog Fingerprint Auth Dialog Success Fingerprint Auth Dialog Fail

iOS

For the iOS platform, you need to use the cordova-plugin-touch-id.

This plugin allow you to scan the fingerprint of your user with the TouchID sensor (iPhone 5S).

  • Compatible with Cordova Plugman.
  • Minimum iOS version is 8 (error callbacks will be gracefully invoked on lower versions).
  • Requires a fingerprint scanner, so an iPhone 5S or newer is required.

To install this plugin on your project execute the following command on your command prompt:

cordova plugin add cordova-plugin-touch-id
#Or clone from the repo
cordova plugin add https://github.com/EddyVerbruggen/cordova-plugin-touch-id

After a succesfully installation, an object will be registered in window.plugins named touchid.

First you'll want to check whether or not the user has a configured fingerprint scanner (to provide fallback for users without an iPhone 5s or lower), use the success callback to use the other methods.

window.plugins.touchid.isAvailable(
    function() {
        alert('available!')
    }, // success handler: TouchID available
    function(msg) {
        alert('not available, message: ' + msg)
    } // error handler: no TouchID available
);

If the onSuccess handler was called, you can scan the fingerprint. There are two options: verifyFingerprint andverifyFingerprintWithCustomPasswordFallback. The first method will offer a fallback option called 'enter passcode' which shows the default passcode UI when pressed. The second method will offer a fallback option called 'enter password' (not passcode) which allows you to provide your own password dialog.

window.plugins.touchid.verifyFingerprint(
    'Scan your fingerprint please', // this will be shown in the native scanner popup
    function(msg) {
        alert('ok: ' + msg);
    }, // success handler: fingerprint accepted
    function(msg) {
        alert('Something is wrong: ' + JSON.stringify(msg));
    } // error handler with errorcode and localised reason
);

Scan fingerprint

The errorhandler of the method above can receive an error code of -2 which means the user pressed the 'enter password' fallback.

window.plugins.touchid.verifyFingerprintWithCustomPasswordFallback(
  'Scan your fingerprint please', // this will be shown in the native scanner popup
   function(msg) {
       alert('ok: ' + msg)
   }, // success handler: fingerprint accepted
   function(msg) {
       alert('not ok: ' + JSON.stringify(msg))
   } // error handler with errorcode and localised reason
);

This will render a button labelled 'Enter password' in case the fingerprint is not recognized. If you want to provide your own label ('Enter PIN' perhaps), you can use the named function verifyFingerprintWithCustomPasswordFallbackAndEnterPasswordLabel (added in version 3.1.0):

window.plugins.touchid.verifyFingerprintWithCustomPasswordFallbackAndEnterPasswordLabel(
    'Scan your fingerprint please', // this will be shown in the native scanner popup
    'Enter PIN', // this will become the 'Enter password' button label
    function(msg) {
       alert('ok: ' + msg)
    }, // success handler: fingerprint accepted
    function(msg) {
       alert('not ok: ' + JSON.stringify(msg))
    } // error handler with errorcode and localised reason
);

Increasing the security on iOS

Since iOS9 it's possible to check whether or not the list of enrolled fingerprints changed since the last time you checked it. It's recommended you add this check so you can counter hacker attacks to your app. See this article for more details.

So instead of checking the fingerprint after isAvailable add another check. In case didFingerprintDatabaseChange returnstrue you probably want to re-authenticate your user before accepting valid fingerprints again.

window.plugins.touchid.isAvailable(
    // success handler; available
    function() {
      window.plugins.touchid.didFingerprintDatabaseChange(
          function(changed) {
            if (changed) {
              // re-auth the user by asking for his credentials before allowing a fingerprint scan again
            } else {
              // call the fingerprint scanner
            }
          }
      );
    },
    // error handler; not available
    function(msg) {
      // use a more traditional auth mechanism
    }
);

Multiplatform wrapper

As the code of the plugins vary, you need to check wheter the OS of the device is iOS or Android to prevent errors. If you are working in both platforms, you can use the following wrapper function to check when to use which code:

function verifyFingerprint(callbacks){
    var triggerCallbackIfExists = function(callback_name){
        if(typeof(callbacks[callback_name]) == "function"){
            // Execute function
            callbacks[callback_name]();
        }
    };

    // if IOS
    if(!!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)){
        triggerCallbackIfExists("ios");
    // If Android
    }else if(navigator.userAgent.toLowerCase().indexOf("android") > -1){
        triggerCallbackIfExists("android");
    // If other OS
    }else{
        triggerCallbackIfExists("others");
    }
}

And use it like:

verifyFingerprint({
    ios: function(){
        // Here the code to verify the fingerprint only on IOS
    },
    android: function(){
        // Here the code to verify the fingerprint only in Android
    },
    others: function(){
        // alert("There's no plugin to verify fingerprint in this platform");
    }
});

Note that is up to you to check if the device supports the fingerprint feature with the plugin itself.

Have fun

Become a more social person