Toto NaBendo
Toto NaBendo

Reputation: 342

Loop expo biometric authentication until success

I'm trying to implement a biometric authentication (faceID / fingerprint) on Android using React-native with Expo.

Using the LocalAuthentication.authenticateAsync() function, the user is able to authenticate with his biometry. But if it fail, the user have to press the biometric authentication again.

So i tried a little trick with a recursif or do while loop but the result is strange :

const scanFingerPrint = async () => {
        try {
            const results = await DeviceService.biometricAuthentication();
            if (results.success) {
                SecureStoreService.getCredential()
                    .then(credentials => onScan(credentials));
            } else {
                ShakeAnimation(animatedValueModal);
                return scanFingerPrint();
            }
        } catch (e) {
            console.log(e);
        }
    };

With this code, if the user fail the biometric authentication, it will pass in the "else" infinitly...

So I was wondering how to handle that on android.

Upvotes: 5

Views: 2593

Answers (3)

Toto NaBendo
Toto NaBendo

Reputation: 342

Expo provide an "error" key on the results of the local authentication. To not handle an hardware error i used this :

if (!results.success) {
                switch (results.error) {
                    case "lockout":
                        setLocked(true);
                        break;
                    case "authentication_failed" || "too_fast":
                        ShakeAnimation(animatedValueModal);
                        await scanBiometric();
                        break;
                    case "user_cancel" :
                        break;
                    default:
                        ShakeAnimation(animatedValueModal);
                        break;
                }
            }

Upvotes: 0

Jaydeep Galani
Jaydeep Galani

Reputation: 4961

You can pass function variable for attempts.

see this,

const scanFingerPrint = async (remainingAttempts = 5) => {  // you can change 5 as per your choice
  try {
    const results = await DeviceService.biometricAuthentication();
    if (results.success) {
      SecureStoreService.getCredential().then(credentials =>
        onScan(credentials)
      );
    } else {
      ShakeAnimation(animatedValueModal);
      if (remainingAttempts) {
        remainingAttempts--;
        scanFingerPrint(remainingAttempts);
      } else {
        alert("You have exceeded max scan limit.");
      }
    }
  } catch (e) {
    console.log(e);
  }
};

and you do not need to change anything else. not event your first time function call.

Upvotes: 0

Ankit Makwana
Ankit Makwana

Reputation: 2451

You can handle it manually using a variable. First create variable retryCount inside constructor or as a property of class so that it is accessible in each function.

constructor(props) {
    super(props);
    this.retryCount = 3; 
}

set the value of retryCount before calling scanFingerPrint function.

this.retryCount = 3; //number of attempts you want to provide

Now modify function like below to prevent infinite loop:

const scanFingerPrint = async () => {
    try {
        if (this.retryCount <= 0){
            //exceeded the number of attempts..try again after a minute
        } else{
            this.retryCount--;
            const results = await DeviceService.biometricAuthentication();
            if (results.success) {
                SecureStoreService.getCredential()
                    .then(credentials => onScan(credentials));
            } else {
                ShakeAnimation(animatedValueModal);
                return scanFingerPrint();
            }
        }
    } catch (e) {
        console.log(e);
    }
};

Upvotes: 0

Related Questions