Apple Face ID / Touch ID

Overview

Provide your users with a seamless login experience using Apple's Face ID and Touch ID authentication.

Fingerprint technology has been accessible to apps running on iOS devices starting with the iPhone 5s running iOS 9.0. This module enables this convenient and secure means of authenticating users of your app.

Median's Apple Face ID / Touch ID plugin uses Median JavaScript Bridge commands to secure storage and retrieval of user credentials. Communication from the web page to the native apps is done by opening a specific URL with certain query parameters, detailed below.

Responses from the native app are delivered to a callback function in the window's JavaScript context. The plugin module allows the storage of a secret string. The contents and format of the string should be decided by the website developer. It may contain a JSON object containing the username and password, an authentication token, or anything else that would authenticate the user.

The first step is to check for the presence and availability of the fingerprint reader. If there is no fingerprint reader, or if the user has not enrolled any fingerprints, a fingerprint dialog should not be shown. If fingerprints are available, then the status check will also indicate the presence of a previously saved secret.

Once a user has logged in, and has fingerprints enrolled, the website may save the secret. We use the iOS Keychain technology, which in turn leverages cryptographic hardware, to ensure that the secret cannot be retrieved without fingerprint 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 the 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 their fingerprint. If the fingerprint check is successful, the secret will be sent to the website via the JavaScript callback. If not, the callback will receive an error.

👍

Developer Demo

Display our demo page in your app with the Face ID / Touch ID 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 if Touch ID is available. If it is, 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.

↔️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});

function median_status_afterlogin(data) {
    if (data && data.hasTouchId) {
    	var secret = JSON.stringify({
            username: username,
            password: password
        });
        
        median.auth.save({'secret': secret});
    }
}

// Promise method
median.auth.status().then(function (result) {
    if (result && result.hasTouchId) {
    	var secret = JSON.stringify({
            username: username,
            password: password
        });
        
        median.auth.save({'secret': secret});
    }
}

Learn more about using promises and the Median JavaScript Bridge.

In this example, we have saved the username and password as the secret. You may choose to save an authentication token instead.

Check for secret on login page

↔️Median JavaScript Bridge

On the login page, you will need to know whether or not to prompt for TouchID credentials. Start by getting the status:

median.auth.status({'callbackFunction': median_status_beforelogin});

function median_status_beforelogin(data) {
   if (data && data.hasTouchId && data.hasSecret) {
       // Prompt the user to use the fingerprint 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
    }
}

// Promise method
median.auth.status().then(function (result) {
   if (result && result.hasTouchId && result.hasSecret) {
       // Prompt the user to use the fingerprint to log in
       median.auth.get({'callbackFunction': median_secret_callback});
   }
}

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 FaceID / Touch ID availability

↔️Median JavaScript Bridge

Run the JavaScript function:

median.auth.status({'callbackFunction': CALLBACK});

Callback is required. The app will execute CALLBACK with an object parameter containing the fields:

  • hasTouchId: true or false. Indicates if the device is running iOS 9+ and there are fingerprints enrolled, or FaceID is enabled.
  • biometryType: ‘touchId’, ‘faceId’, or ‘none’. This field is populated on iOS only to differentiate between TouchID and FaceID.
  • hasSecret: true or false

Saving a secret

Typically you will want to first check that Face ID / Touch ID is available via the status function above and then save the secret.

↔️Median JavaScript Bridge

Run the JavaScript function:

median.auth.save({'secret': secret});

callbackFunction is optional and will be called after the save operation with a success parameter.

Getting a secret

↔️Median JavaScript Bridge

Run the JavaScript function:

median.auth.get({'callbackFunction': CALLBACK, 'prompt': 'PROMPT'});

Callback is required. Prompt is optional, and provides a message that can be displayed when iOS requests the user touch the fingerprint sensor. The app will execute CALLBACK with an object parameter containing the fields:

  • success: true or false
  • error: provided success is false (see error codes below)
  • secret: the previously stored secret
    Another optional query parameter is callbackOnCancel. If set to 1 and the user cancels the authentication, the callback will be run with success=false, error=userCanceled. If callbackOnCancel is not set (or set to 0), the callback will not be run.

Deleting a secret

↔️Median JavaScript Bridge

Run the JavaScript function:

median.auth.delete({'callbackFunction': CALLBACK});

Callback is optional. The app will execute CALLBACK with an object parameter containing the fields:

  • success: true or false
  • error: 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

White-listing access

By default, any page loaded in your app will be able to use Median JavaScript Bridge to retrieve secrets. If you are allowing any domains you do not control to be loaded within your app, we strongly recommend whitelisting only certain domains to access this plugin.

To do so, go to the Native Plugins page of your Median project, click Settings for this plugin and add your whitelisted URLs (comma separated for multiple URLs) as shown below:

2634

Whitelisted URLs