Android Biometric
Overview
Median's Android Biometric Authentication native plugin uses Median JavaScript Bridge commands to securely store and retrieve user credentials. The plugin supports both "Strong" and "Weak" biometrics. Strong incorporates biometric hardware to verify the user's identity, e.g fingerprint or IR facial scan. Weak includes less hardware level security, e.g. camera only. It is up to you as the web developer implementing this native plugin to specify the minimum level of biometrics to accept, and the resultant security of your app.
When designing your implementation the first step is to check for the presence and availability of biometric capabilities. If there are no biometric capabilities available a biometric login dialog should not be displayed to the end user. If biometrics are available, then the status check will also indicate the presence of a previously saved secret.
Once a user has successfully logged in you may save a secret to the device that can be used to login again in the future. We use the Android Keystore, which in turn leverages on-device cryptographic hardware, to ensure that the secret cannot be retrieved without biometric authentication from the user. Note that saving the secret does not require any specific user interaction on the device.
The next time the user needs to log in to your website, and the status check indicates a secret is available, the website should attempt to retrieve the secret from the device. At that point, the user will be shown a dialog prompting them to authenticate via biometrics. If the biometrics are provided successfully, the secret will be released by the Android Keystore and returned via a promist or JavaScript callback. If biometrics are unsuccessful, an error will be returned.
Developer Demo
Display our demo page in your app with the Face ID / Touch ID Android Biometric Native Plugin active to test during development https://median.dev/auth/
Implementation Guide
Once the premium module has been added to your app, you may use the following Median JavaScript Bridge commands to access its functionality.
This guide assumes a working publicly-accessible website (or test site) with a username and password login system.
Save secret on successful login
After a user successfully logs in to your website with their username and password, check to see the device has biometric capabilities available. If biometrics are available then seamlessly save a secret for future retrieval. The secret must be a single string, and can be a combination of the username and password or an authentication token. You may specify a minimum biometric level to support, either strong
or weak
.
↔️Median JavaScript Bridge
For example, you may embed this JavaScript into your post-login page:
var username = 'andy' var password = 'password'; median.auth.status({'callbackFunction': median_status_afterlogin}); // returns promise function median_status_afterlogin(data) { if (data && data.hasTouchId) { var secret = JSON.stringify({ username: username, password: password }); median.auth.save({ 'secret': secret, 'minimumAndroidBiometric': 'strong' }); } }
Tip: Some JS Bridge commands return promises. They are usually declared as such through a comment to help you identify them. Learn More.
In this example, we have saved the username and password as the secret. You may choose to save an authentication token instead. We have specified the minimumAndroidBiometric
as strong
which is the default biometric level.
Check for secret on login page
↔️Median JavaScript Bridge
On the login page, you will need to know whether or not to prompt for biometric login. Start by getting the status:
median.auth.status({'callbackFunction': median_status_beforelogin}); // returns promise function median_status_beforelogin(data) { if (data && data.hasTouchId && data.hasSecret) { // Prompt the user to use biometrics to log in median.auth.get({'callbackFunction': median_secret_callback}); } } function median_secret_callback(data) { if (data && data.success && data.secret) { var credentials = JSON.parse(data.secret); var username = credentials.username; var password = credentials.password; // Use username and password to do login here, // e.g. an http post or ajax request } else { // Allow manual entry } }
Once the
median_secret_callback
function is called with the previously saved secret, it should perform a request to log in the user. If the credentials are incorrect, you should delete the secret and allow manual login by running the function:// delete secret if credentials are incorrect median.auth.delete({'callbackFunction': CALLBACK});
Median JavaScript Bridge Reference
Retrieving biometric availability
↔️Median JavaScript Bridge
Run the JavaScript function:
median.auth.status({ 'minimumAndroidBiometric': 'strong' | 'weak', // optional, default is 'strong' 'callbackFunction': CALLBACK // optional if callback is used rather than promise });
The app will return a promise, or if provided execute CALLBACK, with an object parameter containing the fields:
hasTouchId
:true
orfalse
. Set totrue
on Android devices with fingerprints enrolled.hasSecret
:true
orfalse
Saving a secret
Typically you will want to first check that biometrics are available via the status function above and then save the secret.
↔️Median JavaScript Bridge
Run the JavaScript function:
median.auth.save({ 'secret': secret, 'minimumAndroidBiometric': 'strong' | 'weak', // optional, default is 'strong' 'callbackFunction': CALLBACK // optional if callback is used rather than promise });
The app will return a promise, or if provided execute CALLBACK, with an object with a
success
field
Getting a secret
↔️Median JavaScript Bridge
Run the JavaScript function:
median.auth.get({ 'callbackFunction': CALLBACK, // optional if callback is used rather than promise 'minimumAndroidBiometric': 'strong' | 'weak', // optional, default is 'strong' 'prompt': 'PROMPT', 'callbackOnCancel': INTEGER // optional });
Prompt is only available for iOS and it has been included above to ensure cross-platform compatibility. The app will return a promise, or if provided execute CALLBACK, with an object parameter containing the fields:
success
: true or falseerror
: provided success is false (see error codes below)secret
: the previously stored secret
callbackOnCancel
is optional. If set to1
and acallbackFunction
has been provided, when the user cancels the authentication the callback function will be invoked withsuccess=false
,error=userCanceled
. IfcallbackOnCancel
is not set (or set to 0), the callback will not be run on cancel.
Deleting a secret
↔️Median JavaScript Bridge
Run the JavaScript function:
median.auth.delete({ 'callbackFunction': CALLBACK // optional if callback is used rather than promise });
The app will return a promise, or if provided execute CALLBACK, with an object parameter containing the fields:
success
: true or falseerror
: provided if success is false
Possible error values
In general, you will only need to handle authenticationFailed in the "get secret" request.
duplicateItem
itemNotFound
authenticationFailed
genericError
userCanceled
unimplemented
Limiting access to allowed URLs
By default, any page loaded in your app will be able to use Median JavaScript Bridge to retrieve secrets. If you are allowing domains you do not control to be loaded within your app we strongly recommend restricting access to only specified Allowed URLs.
To do so, go to the Native Plugins page of your Median app, click Settings for the Face ID/Touch ID Android Biometric plugin and add your Allowed URLs (comma separated for multiple URLs) as shown below:
Updated about 2 months ago