Open MatthewPringle opened 6 years ago
@MatthewPringle some alternatives..?
Does anyone know of an alternative plugin? I need one that supports keychain storage like this one, not just fingerprint authentication.
Removed
What about using one or more fingerprint/face auth plugins with https://github.com/Crypho/cordova-plugin-secure-storage ? Looking into it myself (raised an issue about its underlying dependency, but the repo itself seems good).
https://github.com/niklasmerz/cordova-plugin-fingerprint-aio looks good am about to try that in an app
@mzealey , did you try?
Yes works great out of the box.
How do you save/retrieve user passwords in keychain using this plugin, it seems to have no option to handle this case, am I wrong? If yes, code sample would be great.
@edubskiy I can put up an example of this plugin cordova-plugin-keychain-touch-id working.
It is in Ember though and uses computed values / services so wouldn't be so straight forward. But it does work and has been used in a couple of applications I have used.
/ App - Service - Biometrics / / ---------------------------------------------------------------------------------------------------- /
/ Import / import EmberService from '@ember/service'; import { inject as service } from '@ember/service'; import { computed } from '@ember/object'; import { isPresent } from '@ember/utils';
/ Export / / ---------------------------------------------------------------------------------------------------- / export default EmberService.extend({
/* Setup */
/* ------------------------------------------------------------------------------------------------ */
type: false, saved: false,
/* Services */
/* ------------------------------------------------------------------------------------------------ */
authService: service( 'authentication' ),
dialogService: service( 'dialog' ),
storageService: service( 'storage' ),
/* Active */
/* ------------------------------------------------------------------------------------------------ */
active: computed( 'type' , 'saved' , function() {
return this.get( 'type' ) && this.get( 'saved' );
}),
/* Label */
/* ------------------------------------------------------------------------------------------------ */
label: computed( 'type' , function() {
/* Touch ID */
if ( this.get( 'type' ) === 'touch' ) {
return 'Touch ID';
/* Face ID */
} else if ( this.get( 'type' ) === 'face' ) {
return 'Face ID';
/* Biometric ID */
} else {
return 'Biometric ID';
}
}),
/* Status */
/* ------------------------------------------------------------------------------------------------ */
status: function() {
/* Check Plugin */
if ( window.cordova !== undefined && window.plugins !== undefined && window.plugins.touchid !== undefined ) {
/* Setup */
var self = this;
/* Available */
window.plugins.touchid.isAvailable( function( type ) {
/* Set Type */
self.set( 'type' , type );
/* Unavailable */
}, function() {
/* Reset Type */
self.set( 'type' , false );
});
}
},
/* Authenticate */
/* ------------------------------------------------------------------------------------------------ */
authenticate: function() {
/* Check Plugin */
if ( window.cordova !== undefined && window.plugins !== undefined && window.plugins.touchid !== undefined ) {
/* Setup */
var self = this;
/* Load Password */
window.plugins.touchid.verify( this.get( 'storageService' ).load( 'username' ) , 'Access your App Name account' , function( password ) {
/* Authenticate */
self.get( 'authService.authenticate' ).perform( self.get( 'storageService' ).load( 'username' ) , password );
/* Error */
}, function() {
/* Reset */
self.set( 'saved' , false );
/* Reset Question */
self.get( 'storageService' ).save( 'biometrics' , '' );
});
}
},
/* Restore */
/* ------------------------------------------------------------------------------------------------ */
restore: function() {
/* Update Status */
this.status();
/* Check Response */
if ( window.cordova !== undefined && this.get( 'storageService' ).load( 'biometrics' ) !== 'rejected' && isPresent( this.get( 'storageService' ).load( 'username' ) ) ) {
/* Check Plugin */
if ( window.plugins !== undefined && window.plugins.touchid !== undefined ) {
/* Setup */
var self = this;
/* Key Exists */
window.plugins.touchid.has( this.get( 'storageService' ).load( 'username' ) , function() {
/* Set Saved */
self.set( 'saved' , true );
/* Key Doesnt Exist */
}, function() {
/* Reset Saved */
self.set( 'saved' , false );
/* Reset Question */
self.get( 'storageService' ).save( 'biometrics' , '' );
});
}
}
},
/* Save */
/* ------------------------------------------------------------------------------------------------ */
save: function( username , password ) {
/* Check Response */
if ( window.cordova !== undefined && this.get( 'storageService' ).load( 'biometrics' ) !== 'rejected' && this.get( 'type' ) ) {
/* Check Plugin */
if ( window.plugins !== undefined && window.plugins.touchid !== undefined ) {
/* Ask Question */
if ( !this.get( 'saved' ) ) {
/* Ask Question */
this.question( username , password );
/* Save */
} else {
/* Save Password */
window.plugins.touchid.save( username , password , false , function() {} , function() {} );
}
}
}
},
/* Reset */
/* ------------------------------------------------------------------------------------------------ */
reset: function() {
/* Check Plugin */
if ( window.cordova !== undefined && window.plugins !== undefined && window.plugins.touchid !== undefined ) {
/* Check Saved */
if ( this.get( 'saved' ) ) {
/* Delete Password */
window.plugins.touchid.delete( this.get( 'storageService' ).load( 'username' ) , function() {} , function() {} );
/* Reset */
this.set( 'saved' , false );
}
/* Reset Question */
this.get( 'storageService' ).save( 'biometrics' , '' );
}
},
/* Question */
/* ------------------------------------------------------------------------------------------------ */
question: function( username , password ) {
/* Check Plugin */
if ( window.cordova !== undefined && window.plugins !== undefined && window.plugins.touchid !== undefined ) {
/* Setup */
var self = this;
/* Show Question */
this.get( 'dialogService' ).confirm( 'App Name' , 'Do you want to use your ' + this.get( 'label' ) + ' to log in next time?',
/* Answer - Yes */
/* ------------------------------------------------------------------------------------ */
function() {
/* Save Password */
/* -------------------------------------------------------------------------------- */
window.plugins.touchid.save( username , password , true , function() {
/* Set Saved */
self.set( 'saved' , true );
/* Show Notification */
self.get( 'dialogService' ).notification( 'App Name' , 'Continue' , 'Your password has been saved.' );
/* Error */
/* -------------------------------------------------------------------------------- */
}, function() {
/* Set Saved */
self.set( 'saved' , false );
/* Show Notification */
self.get( 'dialogService' ).notification( 'App Name' , 'Continue' , 'An error has occurred. Your password has not been saved.' );
});
/* Answer - No */
/* ------------------------------------------------------------------------------------ */
}, function() {
/* Set Saved */
self.set( 'saved' , false );
/* Save Response */
self.get( 'storageService' ).save( 'biometrics' , 'rejected' );
}
);
}
}
});
For the above...
Storage Service just saves a cookie with the username and if the user has rejected using biometrics
Dialog Service is just a wrapper for the Cordova notifications plugin ( the code has to work on a website as well and would adapt to use javascript notifications in place of Cordova notifications )
Auth Service is a separate service for authenticating users with the server, you can replace this with your own once you have retrieved the password from the keychain.
@edubskiy no I use window.plugins.touchid.save( username , password , false , function() {} , function() {} );
I save the username in a cookie / local storage. I recall the username and then I can pass that to
window.plugins.touchid.has( this.get( 'storageService' ).load( 'username' ) , function() {
To check if the user has a stored username / password protected by biometrics
And then I use
window.plugins.touchid.verify( this.get( 'storageService' ).load( 'username' ) , 'Access your App Name account' , function( password ) {
To retrieve the password using the username + biometrics
The basic idea is that on a login page, you would save a cookie with the username after first login, ask about using Biometrics for future logins etc... ( see question: function( username , password ) { )
When the user sees the login page again, having checked to see if a cookie exists, it autofills the username part of the login form.
I then query the touch id plugin to see if a username exists in the touch id password store.
If so I can present the user with a "Login with Biometrics" button rather than asking them for a password.
They can then provide biometric authentication and the device passes me back the password.
You would also want to fire the status: function() on app init so you know about the capabilities of the device.
@MatthewPringle , thank you, but I thought you showed the code for this plugin https://github.com/niklasmerz/cordova-plugin-fingerprint-aio We also have similar code you showed, and 95% of the time it really works ok, but in some cases we have complains from users when touchid.save is not working correctly and it seems there is no support for plugin any more that is why we have to replace it with alternative.
@edubskiy no it is for this plugin, after a lot of testing the code we used seems to work fine across all devices and platforms we tested on. Due to problems with other plugins we decided to use this one for the current releases.
The code we wrote is a little different from their examples, such as
window.plugins.touchid.save( username , password , false , function() {} , function() {} );
Notice the save function has one more param than the one in their example
This plugin no longer seems to be getting updates.
It has numerous issues that can cause build failures and crashes on both iOS and Android.
The docs are incorrect.
I would recommend not using this plugin as it will only cause you issues.