Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do you store the user's password in the iOS / Android keychain when enrolling in biometrics? #86

Open
justintoth opened this issue Apr 17, 2021 · 0 comments

Comments

@justintoth
Copy link

I'm attempting to implement this nativescript-fingerprint-auth package in my NativeScript / Angular app, however I'm having trouble understanding something... The code examples show how to retrieve the user's password after they have already enrolled in biometrics (Face Id or Touch Id). Basically you call fingerprintAuth.verifyFingerprint and then you get back a "userEnteredPassword" that you can populate on the signin form and then auto-sign the user in.

However, nowhere in the docs can I find where when you first enroll the user in biometrics do you pass in the password that you want to store in the iOS / Android password store / keychain. I tried the demo code, and indeed when I call the verifyFingerprint method after having already enrolled them, the userEnteredPassword returned is undefined. So, am I missing something or does the demo code not show how to store the password?

Here is my code, in case it helps:

export class LoginComponent extends BaseComponent {
    public emailAddress: string;
    public password: string;
    private fingerprintAuth: FingerprintAuth;
    public biometricTouchAvailable: boolean;
    public biometricFaceAvailable: boolean;
    public enrollInBiometrics = true;
    public loading = false;
    public validators = new Validators();

    @AutoGC()
    public subscription: Subscription;

    constructor(
        private storageService: StorageService
    ) {
        super();
        this.emailAddress = this.user ? this.user.emailAddress : this.authService.emailAddress;
        this.fingerprintAuth = new FingerprintAuth();
        // Check availability of biometrics.
            this.fingerprintAuth.available().then((result: BiometricIDAvailableResult) => {
                this.biometricFaceAvailable = result.face;
                this.biometricTouchAvailable = result.touch;
            });
    }

    public submit(skipBiometricsCheck = false) {
        if (!skipBiometricsCheck && this.shouldValidateBiometrics) {
            this.enrollOrValidateBiometrics();
            return;
        }
        if (this.validators.focusInvalid())
            return;
        this.loading = true;
        this.subscription = this.authService.authenticate({ emailAddress: this.emailAddress, password: this.password }).subscribe(
            user => {
                this.loading = false;
                if (this.shouldEnrollBiometrics)
                    this.enrollOrValidateBiometrics();
                else
                    this.authService.redirect(user);
            },
            exc => {
                showAlert(exc.error?.description || exc.toString());
                this.loading = false;
            },
        );
    }

    private get shouldValidateBiometrics() {
        if (!this.biometricFaceAvailable && !this.biometricTouchAvailable)
            return false;
        if (!this.enrolledInBiometrics)
            return false;
        if (!this.emailAddress)
            return false;
        if (this.password)
            return false;
        return true;
    }

    private get shouldEnrollBiometrics() {
        if (!this.biometricFaceAvailable && !this.biometricTouchAvailable)
            return false;
        if (this.enrolledInBiometrics)
            return false;
        if (!this.enrollInBiometrics)
            return false;
        return true;
    }

    private enrollOrValidateBiometrics() {
        const enroll = !this.enrolledInBiometrics;
        // TODO:[JT] On biometrics enroll, how do we store the app password in the keychain?
        console.log(`${enroll ? 'Enroll' : 'Validate'} biometrics`);
        this.fingerprintAuth.verifyFingerprint(
            {
                title: `Enable ${this.biometricFaceAvailable ? 'Face Id' : 'Touch Id'}`,
                message: `Sign into Housters using ${this.biometricFaceAvailable ? 'Face Id' : 'Touch Id'}`, 
                useCustomAndroidUI: true
            })
            .then((enteredPassword?: string) => {
                let succeeded = false;
                if (enroll) {
                    console.log('Successfully enrolled in biometric identification');
                    this.enrolledInBiometrics = true;
                    succeeded = true;
                } else {
                    // compare enteredPassword to the one the user previously configured for your app (which is not the users system password!)
                    if (enteredPassword) {
                        this.password = enteredPassword;
                        console.log('Biometric identification is already set up, attempting signin with enteredPassword: ' + enteredPassword);
                        succeeded = true;
                    } else
                        console.error('Biometric identification is already set up, but failed with empty enteredPassword: ' + enteredPassword);
                }
                if (succeeded) {
                    enroll ?
                        this.authService.redirect(this.user) :
                        this.submit(true);
                }
            })
            .catch(err => {
                console.error(`Biometric identification failed: ${JSON.stringify(err)}`);
                this.submit(true);
            });
    }

    private get enrolledInBiometrics() {
        return (Boolean)(this.storageService.get(StorageCacheKeys.ENROLLED_IN_BIOMETRICS)) || false;
    }

    private set enrolledInBiometrics(value) {
        this.storageService.set(StorageCacheKeys.ENROLLED_IN_BIOMETRICS, value);
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant