Integrating LaunchKey with Android

This document walks you through integrating LaunchKey with Android apps.

Requirements

Android Versions

The Authenticator SDK supports the following versions of Android:

Minimum: 4.0.3 (API level 15)
Target: 6.0 (API level 23)

As for versions of dependencies, check the dependencies listed under the "Integration Steps" section and potential changes with every update under the "Changes with v4.x" section.

Permissions

To enable some features, you must declare some permissions in the AndroidManifest.xml file (and handled at runtime if the app is running on Android 23 and up).

Here's a high-level list of permissions automatically declared by the manifest in the SDK that should be automatically merged by Android Studio/Gradle. Keep this in mind if the building process manually modifies the manifest for any reason.

...
<!-- IF INTERESTED IN SUPPORTING THE NOW-DEPRECATED PEBBLE KIT SDK -->
<uses-sdk tools:overrideLibrary="com.getpebble.android.kit"/>

<uses-permission android:name="android.permission.USE_FINGERPRINT"/>

<!-- permission required by Samsung's Pass SDK -->
<uses-permission android:name= "com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY"/>

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

<!-- Stated so the Camera permission does not make this feature an implicit hard requirement -->
<uses-feature android:required="false" android:name="android.hardware.camera" />
<uses-feature android:required="false" android:name="android.hardware.camera.autofocus"/>
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />

<!-- Optional: Improves anonymous metrics -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<!-- IF USING GOOGLE MAPS... -->
<!-- Permissions required for Google Maps v2 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Google Maps API requires OpenGL ES 2 -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />

Due to changes in the Authenticator SDK, Push Notification reception is not internally handled by the SDK in v4.0.0 and up. If you are still using a version below v4.0.0, we suggest migrating over to a newer version. You can check the Migrating section under "Changes with v4.x" later in this document. If still using a version that still handles the reception of Push Notifications internally, keep these in mind

...
<!-- IF RELYING ON GCM -->
<!-- Permissions required for GCM -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

Note

While v4.0.0+ does not handle the reception of Push Notifications, they all handle the payload and updated device tokens relayed back by the implementing application.

Setting Up the LaunchKey Service

Via LaunchKey Authenticator App

Before integrating the LaunchKey Authenticator SDK with your app, an administrator must complete the following steps:

  1. From an Android device, launch the Google Play store.
  2. Search for the LaunchKey Authenticator app, then download and install it.
  3. Run the LaunchKey Authenticator app and tap Get Started.
  4. Complete the Link page. This includes:
    • A username and device name. You will use this username to log into the LaunchKey Admin Center. The device name will appear when you review linked devices.
    • Choose which communication channel you want to use to complete account creation and device registration. You can choose Email and/or SMS. Accept the terms and agreements, then tap Done.
  5. Based on the linking method(s) you chose, you will receive an email and/or text message with a link that you must follow to complete account creation and link your device to the LaunchKey Admin Center.
  6. Now that the device is configured, you must associate it with a service in the LaunchKey Admin Center. From a browser, open the LaunchKey Admin Center at https://admin.launchkey.com/login.
  7. To log in, enter the username that you entered into the LaunchKey Authenticator app when you linked the device.
  8. On the device, authorize the login. If any security factors have been enabled, you will be prompted to complete them before you can complete authorization.
  9. Now that you are in the LaunchKey Admin Center, click the left navigation button and select Organizations. The All Organizations page appears.
  10. Click the New Organization button. The Create New Organization screen appears.
  11. Enter a name for the organization, provide your name and email address (or name and email address of an admin user). Complete the Create New Organization Screen.
  12. The user whose email you entered will receive a confirmation email. Click the confirmation email to complete creation of the organization.
  13. Back in the LaunchKey Admin Center, open the organization you created. Expand the menu button on the left of the screen and select Organizations, then click the organization.
  14. From within the organization, select the Directories tab.
  15. Click the New Directory button to create a new directory. Enter a name for the directory and click the Submit button.
  16. Directory details appear. From here, on the General tab, you can see a Authenticator SDK Keys list. Capture the Authenticator SDK Key. You will need it later when integrating the LaunchKey SDK into your app.
  17. Also on the General tab, under Services, click the NEW SERVICE button. The Create New Service screen appears.
  18. Enter a name and description for the service. Optionally choose an avatar file, read and accept the Terms of Service and click the Create Service button.

You are now ready to integrate the LaunchKey SDK into your mobile apps.

Integrating the Android SDK into Your App

Integration Overview

At a high level, integrating the LaunchKey SDK for Android into your app includes the following steps:

  1. Adding the SDK as a dependency in Android Studio.
  2. Provide credentials for the LaunchKey directory.
  3. Run the calls to initialize the SDK and interact with its core features.

Integration Steps

Follow these detailed steps to integrate the LaunchKey SDK for Android into your app:

  1. Download the SDK from https://github.com/iovation/launchkey-android-authenticator-sdk

  2. In Android Studio, add the LaunchKey SDK in your project as an AAR module and then as a dependency.

  3. Make sure you add all dependencies required by the SDK:

    ...
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:support-v4:23.4.0'
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.android.support:design:23.4.0'
    compile 'com.google.android.gms:play-services-base:8.3.0'
    compile 'com.google.android.gms:play-services-location:8.3.0'
    compile 'com.google.android.gms:play-services-maps:8.3.0'
    compile 'com.google.android.gms:play-services-gcm:8.3.0'
    compile 'com.google.android.gms:play-services-wearable:8.3.0'   // Optional for Android Wear devices to show as security factors
    compile 'com.getpebble:pebblekit:3.0.0'
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.squareup.okhttp3:okhttp:3.3.1'
    compile 'org.bitbucket.b_c:jose4j:0.4.4'
    ...
    
  4. To initialize the SDK, build an AuthenticatorConfig object via AuthenticatorConfig.Build and pass it to the singleton instance of AuthenticatorManager. For example:

    //This key can be obtained in a one-time operation just to link the device.
    String mobileSdkKey = ...
    
    //Build AuthenticatorConfig.
    AuthenticatorConfig config = new AuthenticatorConfig.Builder(context, mobileSdkKey).build();
    
    //Get singleton instance of AuthenticatorManager and initialize with AuthenticatorConfig object.
    AuthenticatorManager manager = AuthenticatorManager.getInstance();
    manager.initialize(config);
    
    //Later verify whether the manager has been initialized.
    manager.isInitialized();
    
  5. To enable users to link their devices, specify a linking mechanism. You can enable either QR code scanning or the ability to manually enter their linking code. To do this, use the following code:

    AuthenticatorManager manager = AuthenticatorManager.getInstance();
    //To enable end-users to scan a QR code in order to link their devices:
    manager.startLinkingActivity(this, AuthenticatorManager.LINKING_METHOD_SCAN);
    //Or, to enable end-users to enter their linking codes manually:
    manager.startLinkingActivity(this, AuthenticatorManager.LINKING_METHOD_MANUAL);
    
    //After linking the device, determine the resulting device status:
    if (manager.isDeviceLinked()) {
    //And direct the user to the next step. ake user to a different Activity...
    } else {
    //Or, if linking fails, direct the user to try again.
    }
    
  6. End-users can choose their own security factors. We recommend requiring end-users to choose a minimum number of factors by calling startSecurityActivity() in the AuthenticatorManager instance. For example:

    AuthenticatorManager manager = AuthenticatorManager.getInstance();
    manager.startSecurityActivity(context);
    
  7. You must embed a fragment from the SDK in the authentication activities that will require users to approve or deny pending authentication requqests. To embed this fragment:

    1. You can add the fragment via XML or programmatically. To add it via XML, use the <fragment> tag and set its canonical class via the name property. You can also set other attributes as needed such as id, layout_width, and layout height. For example:

      <Layout
      ...
      >
      ...
      <fragment
          android:id="@+id/authrequestfragment"
          android:name="com.launchkey.android.whitelabel.sdk.ui.AuthRequestFragment"
          android:layout_width="..."
          android:layout_height="..."
      />
      ...
      </Layout>
      
    2. To add it programmatically, instantiate it and make sure that your FragmentManager adds it to the correct container layout. For example:

      //Store the ID of the fragment container
      private static final int FRAGMENT_CONTAINER_ID = R.id.activity_fragment_container;
      //Instantiate a new Fragment via its class (or using Fragment#instantiate(...))
      AuthRequestFragment authRequestFragment = new AuthRequestFragment();
      ...
      //Set Fragment via FragmentManager (or SupportFragmentManager if using AppCompat)
      getFragmentManager()
      .beginTransaction()
      .add(FRAGMENT_CONTAINER_ID, authRequestFragment)
      .commit();
      
    3. Optionally display the Toolbar part of the Fragment. This allows end-users to either deny a pending authentication request or review more information. By default this toolbar is hidden. Additional options include providing custom toolbars or overriding the default XML to display the default toolbar.

      To programmatically display the toolbar, see the following example:

      AuthRequestFragment authRequestFragment = new AuthRequestFragment();
      authRequestFragment.setToolbarVisible(true);
      
    4. When end-users return to the authentication activity, they should see any pending authentication requests. To implement this, check back with the LaunchKey platform for any outstanding requests. The following example also provides the option to manually check for oustanding requests:

      AuthRequestFragment authRequestFragment = new AuthRequestFragment();
      ...
      //When calling onResume() or your own refresh option, use with the following method:
      authRequestFragment.checkForPending();
      
  8. Optionally, provide a method using AuthenticatorManager to enable either the end-user or the app itself to unlink the device. For example:

    AuthenticatorManager manager = AuthenticatorManager.getInstance();
    ...
    SimpleOperationCallback unlinkCallback = new SimpleOperationCallback() {
    
            @Override
            public void onResult(boolean successful, BaseError error, Object o) {
    
                if (successful) {
                    //Inform the end-user that the device has been successfully unlinked
                } else {
                    // There was a problem notifying the LaunchKey Platform even
                    // though the unlinking operation is unlikely to fail.
                    // More details on the error are given with the BaseError object returned if
                    unlinking isn't successful.
                }
            }
        };
    manager.unlinkCurrentDevice(unlinkCallback);
    

This completes the core integration. Continue on to the next section for advanced integration options.

Advanced Integration Options

Now that the Authenticator SDK for Android is integrated and the basics are working, let's move on to more advanced integration options. We'll start by reviewing the technical components that make up advanced integration.

Key Pair Size

.keyPairSize(int)

The Authenticator SDK offers the possibility of setting the size of the key pair generated when linking the device. It can be any valid size value from 2048 up to 4096 bits. The value will be set to the closest valid value if outside of that range and/or invalid. If this is not set in the AuthenticatorConfig object, then the default value will be used (4096). There are constants for common values under AuthenticatorConfig.Builder.KEYSIZE_*. Example:

int keyPairSizeBits = 3072;
//or keyPairSizeBits = AuthenticatorConfig.Builder.KEYSIZE_MEDIUM which represents the same value

AuthenticatorConfig config =
    new AuthenticatorConfig.Builder(...)
    ...
    .keyPairSize(keyPairSizeBits)
    ...
    .build();

Note

We recommend using the default value of 4096 setting a high level of security even if it might take longer to generate on older hardware.

Activation Delay (v3.0.4 and up)

The Authenticator SDK allows you to set an activation delay for passive security factors, such as geo-fences or Bluetooth proximity devices. This is the time it takes for the SDK to add or remove a passive factor. The delay also applies when an end-user toggles the verification setting for a security factor, which changes how the factor is verified during auth requests, for example only when required, or always.

You can set the delay for a range of time between 0 seconds to 24 hours. Provide the value in seconds, for example set it to 600 (or to a simple equation such as 10 * 60) for a delay of 10 minutes.

For example:

final int geofencingDelaySeconds = 20 * 60;     //20 minutes
final int proximityDelaySeconds = 10 * 60;      //10 minutes

manager.initialize(
        new AuthenticatorConfig.Builder(context, mobileSdkKey)
                .activationDelayGeofencing(geofencingDelaySeconds)
                .activationDelayProximity(proximityDelaySeconds)
                ...
                .build());

Warning

Setting the activation delay to 0 can potentially allow anyone to bypass passive security factors. They can do this by adding new, unintended passive factors and setting the verification toggle to only verify when required. If the user then immediately attempts to authenticate, the new passive factor will not be verified. For this reason, we strongly suggest setting the value to a minimum of ten minutes / 600 seconds.

Default Views

The SDK provides default views the enable end-users to interact with their linked devices and active sessions. To use the default views, embed the following fragments either via XML or programmatically, as you did with AuthRequestFragment:

  • Default "Devices" view: In your Activity's or Fragment's layout, add a fragment tag with the android:name property set to com.launchkey.android.authenticator.sdk.ui.fragment.DevicesFragment along with any other properties like layout_width and layout_height.

Example:

<FrameLayout
...
>
...
<!-- "layout_width" and "layout_height" both have "match_parent" to match the parent's dimensions -->
<fragment
    android:id="@+id/defaultDevicesView"
    android:name="com.launchkey.android.authenticator.sdk.ui.fragment.DevicesFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
/>
...
</FrameLayout>
  • Default "Sessions" view: In your Activity's or Fragment's layout, add a fragment tag with the android:name property set to com.launchkey.android.authenticator.sdk.ui.fragment.SessionsFragment along with any other properties like layout_width and layout_height.

Example:

<FrameLayout
...
>
...
<!-- "layout_width" and "layout_height" both have "match_parent" to match the parent's dimensions -->
<fragment
    android:id="@+id/defaultSessionsView"
    android:name="com.launchkey.android.authenticator.sdk.ui.fragment.SessionsFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
/>
...
</FrameLayout>

Managers

The LaunchKey SDK provides managers that make it possible to replace the default views with custom views of the available data, with hooks to specific action associated with each item.

The following managers are available:

  • AuthenticatorManager: The primary manager that must be initialized to enable the end-user to interact with LaunchKey platform. It provides access to device functions such as initialization, linking and unlinking, and security factors.
  • AuthRequestManager: This manager handles authentication requests. It can return the AuthRequest object that contains all the information necessary to display to an end-user about a request. It can also enable the app itself to deny a pending request programmatically. End-user authentication is managed directly by the AuthRequestFragment.
  • DeviceManager: This manager handles all linked devices for the current user. It enables the app to unlink any currently linked devices. This includes the current device, which is equivalent to calling AuthenticatorManager.unlinkCurrentDevice(...).
  • SessionManager: This manager handles all active sessions that the end-user authorized via AuthRequestFragment. It also enables the mobile app to end a particular session, or all of the sessions.

Events and Notifications

The managers provided by the LaunchKey SDK notify recipients regarding events for which they are responsible. The registerForEvent(...) and unregisterForEvent(...) methods enable registration for the events.

Event callbacks return the following properties as part of the onEventResult(...) method:

  • successful (boolean): The result of the request.
  • error: Error that resulted from the request. If successful is true, the error object is null.
  • result: If the request is successful, this is the result object. For example, for DeviceLinkedEventCallback, when the current device has just been linked, this is a device object that contains all of the device properties.

The following table contains all of the events broadcast by each manager.

Event class Description
AuthenticatorManager accepts event callbacks extending AuthenticatorManager.BaseManagerEventCallback
DeviceLinkedEventCallback Event callback when the current device is linked. The result is a Device object representing the device and its basic properties.
DeviceUnlinkedEventCallback Event callback when the current device is unlinked. There is no result object.
AuthRequestManager accepts event callbacks extending AuthRequestManager.BaseManagerEventCallback
GetAuthRequestEventCallback Event callback when the LaunchKey platform is queried about any pending auth requests. The result is of the AuthRequest type.
AuthRequestResponseEventCallback Event callback when there is a response to a pending auth request. The result is a boolean value set to true if the request is authorized by the user.
DeviceManager accepts event callbacks extending DeviceManager.BaseManagerEventCallback
GetDevicesEventCallback Event callback when the list of all linked devices is fetched from the LaunchKey platform. The result is of the List<Device> type.
UnlinkDeviceEventCallback Event callback when a device other than the current device is unlinked per a request via DeviceManager. The result is of the Device type and represents the unlinked device.
SessionManager accepts event callbacks extending SessionManager.BaseManagerEventCallback
GetSessionsEventCallback Event callback when a list of all active sessions have been fetched from LaunchKey. The result is of the List<Session> type.
EndSessionEventCallback Event callback when a particular session has been ended per a request via SessionManager. The result is of the Session type and represents the ended session.
EndAllSessionsEventCallback Event callback when all sessions havae been ended per a request via SessionManager. There is no result object.

Example: AuthenticatorManager Events

The following example uses AuthenticatorManager events to register for event notifications.:

//Define member variables for each callback

DeviceLinkedEventCallback mDeviceLinkedEvent = new DeviceLinkedEventCallback() {
            @Override
            public void onEventResult(boolean successful, BaseError error, Device device) {
                if (successful) {
                    final String deviceName = device.getName();
                    //Notify the End-user that the current device with name 'deviceName' is now linked.
               } else {
                    //Show the appropriate error message based on the 'error' object returned.
                }
            }
        };

DeviceUnlinkedEventCallback mDeviceUnlinkedEvent = new DeviceUnlinkedEventCallback() {
            @Override
            public void onEventResult(boolean successful, BaseError error, Object o) {
                //Notify the End-user the current device has been unlinked and
                // provide option to re-link if they so want.
            }
        };

//Register for both events via AuthenticatorManager (Usually in the onResume() callback of the Activity/Fragment)
AuthenticatorManager manager = AuthenticatorManager.getInstance();
manager.registerForEvents(mDeviceLinkedEvent, mDeviceUnlinkedEvent);

//Then unregister when done with the events (Usually in the onPause() callback of the Activity/Fragment)
manager.unregisterForEvents(mDeviceLinkedEvent, mDeviceUnlinkedEvent);

Example: AuthRequestManager

This manager handles all aspects to do with auth requests. The operational flow is as follows:

  1. Allow a view to get the singleton instance of AuthRequestManager.
  2. Register and unregister for specific events.
  3. React based on the callbacks and update the user interface.
  4. Trigger a request based on end-user actions.

For example:

//Get instance of the manager
AuthRequestManager manager = AuthRequestManager.getInstance();

//Define event callbacks
GetAuthRequestEventCallback getEvent = new GetAuthRequestEventCallback() {

    @Override
    public void onEventResult(boolean successful, BaseError error, AuthRequest authRequest) {

        if (successful) {
            //Create a notification if not in the View of the embedded AuthRequestFragment
            final ServiceProfile serviceProfile = authRequest.getServiceProfile();
            final String message = "Important message by ".concat(serviceProfile.getName());
            createNotificationForEndUser(message);
        } else {
            //Show message based on 'error' object returned
        }
    }
};

AuthRequestResponseEventCallback responseEvent = new AuthRequestResponseEventCallback() {

    @Override
    public void onEventResult(boolean successful, BaseError error, Boolean authorized) {

        if (successful) {
            //Update UI based on 'authorized'
        } else {
            //Show message based on 'error' object returned
       }
    }
};

//Register for events
manager.registerForEvents(getEvent, responseEvent);

//Check for any pending Auth Requests if not obtained already via Push Notifications
//Note: Push notifications require extra setup
manager.check()

//Unregister for events
manager.unregisterForEvents(getEvent, responseEvent);

//If you are providing a custom toolbar or user interface to deny Auth Requests
manager.denyAuthRequest();

Example: DeviceManager

The operational flow is as follows:

  1. Allow a view to get the singleton instance of DeviceManager.
  2. Register and unregister for specific events.
  3. React based on the callbacks and update the user interface.
  4. Trigger a request based on end-user actions.

For example:

//Get an instance of the manager
DeviceManager manager = DeviceManager.getInstance(context);

//Define event callbacks
GetDevicesEventCallback getDevicesEvent = new GetDevicesEventCallback() {

    @Override
    public void onEventResult(boolean successful, BaseError error, List<Device> devices) {

        if (successful) {
            //Update adapter with a new list of Device objects and update the user interface
        } else {
            //Show message based on the 'error' object returned
        }
    }
};

UnlinkDeviceEventCallback unlinkDeviceEvent = new UnlinkDeviceEventCallback() {

    @Override
    public void onEventResult(boolean successful, BaseError error, Device device) {

        if (successful) {
            //Notify how a device has been successfully unlinked--usually a request by the End-user
        } else {
            //Show message based on 'error' object returned
        }
    }
};

//Register for events
manager.registerForEvents(getDevicesEvent, unlinkDeviceEvent);
//Note: If there is already a list of devices, when a new event callback is
// registered, it is immediately notified of the list.

//Request update on list of devices
manager.getDevices();

//Unregister for events
manager.unregisterForEvents(getDevicesEvent, unlinkDeviceEvent);


//Request the unlinking of another device, action usually triggered by the End User


SimpleOperationCallback optionalOneTimeCallback = new SimpleOperationCallback {


   @Override
   public void onResult(boolean successful, BaseError error, Device device) {
       if (successful) {
           //Notify the end-user of the successful unlinking request on the 'device'
        } else {
            //Show a message based on the 'error' object returned
        }
    }
};

Device deviceToBeUnlinked = ...;
manager.unlinkDevice(deviceToBeUnlinked, optionalOneTimeCallback);
//Note: the optional callback can be a 'null' argument

Example: SessionManager

The operational flow to handle active sessions generated by one or more services is as follows:

  1. Allow a view to get the singleton instance of SessionManager.
  2. Register and unregister for specific events.
  3. React based on the callbacks and update the user interface.
  4. Trigger a request based on end-user actions.

For example:

//Get an instance of the manager
SessionManager manager = SessionManager.getInstance(context);

//Define event callbacks
GetSessionsEventCallback getSessionsEvent = new GetSessionsEventCallback() {

    @Override
    public void onEventResult(boolean successful, BaseError error, List<Sessions> sessions) {

        if (successful) {
            //Update the adapter with new list of Session objects and update UI
        } else {
            //Show a message based on 'error' object returned
        }
    }
};

EndSessionEventCallback endSessionEvent = new EndSessionEventCallback() {

    @Override
    public void onEventResult(boolean successful, BaseError error, Session session) {

        if (successful) {
            //Notify the End User that the 'session' has been ended
        } else {
            //Show a message based on the returned 'error' object
        }
    }
};

EndAllSessionsEventCallback endAllSessionsEvent = new EndAllSessionsEventCallback() {

    @Override
    public void onEventResult(boolean successful, BaseError error, Object o) {

        if (successful) {
            //Notify the End User all active sessions have been ended
        } else {
            //Show message based on 'error' object returned
        }
    }
};

//Register for events
manager.registerForEvents(getSessionEvent, endSessionEvent, endAllSessionsEvent);

//Request an update on list of sessions
manager.getSessions();

//Unregister for events
manager.unregisterForEvents(getSessionEvent, endSessionEvent, endAllSessionsEvent);

//End a session
SimpleOperationCallback optionalOneTimeCallback = new SimpleOperationCallback {


    @Override
    public void onResult(boolean successful, BaseError error, Session session) {
        if (successful) {
            //Notify End User that 'session' has been ended
        } else {
            //Show message based on 'error' object returned
        }
    }
};

Session sessionToEnd = ...;
manager.endSession(sessionToEnd, optionalOneTimeCallback);
//Note: the optional callback can be a 'null' argument

Automatic Linking of a Device

If your mobile app is supported by its own backend system, then the backend can generate a valid linking code, directly interacting with the LaunchKey API, and pass it down to the mobile app. This process can be triggered only when the end user has successfully provided traditional credentials to your system which would allow for the device to be automatically linked on their behalf.

This is a scenario that would require deeper integration which would otherwise have the end user type/scan the code themselves instead.

Customizing the User Interface

Overview

You can optionally customize many user interface (UI) elements. To customize the UI, you must define an XML theme that overrides the default theme, and pass the overrides to the SDK via the AuthenticatorConfig method when the SDK is initialized.

Properties Reference

Check the table below for reference on customizable properties. Note: All customization done at runtime (programmatically) requires v4.4 and up.

Element XML Java

Toolbar / App Bar

(color)

Bar at the top of SDK screens with title, menu items, and navigational elements.

  • authenticatorToolbarBackground
  • authenticatorToolbarItems
  • appBar(colorBg, colorItems)

Backgrounds

(Drawable)

Overall backgrounds in SDK screens.

  • authenticatorColorBackground
  • background(drawableBg)

Background Overlays

(color)

Elements overlaying backgrounds.

  • authenticatorColorBackgroundOverlay
  • backgroundOverlay(colorOverlay)

Buttons

(Drawable, color)

Conventional buttons used in SDK screens.

  • authenticatorColorButtonBackground
  • authenticatorColorButtonText
  • button(drawableBg, colorText)
  • button(drawableBg, colorStateListText)

Negative Buttons

(Drawable, color)

Conventional buttons used in SDK screens linked to negative actions.

  • authenticatorColorNegativeWidgetText
  • authenticatorColorNegativeWidgetBackground
  • buttonNegative(drawableBg, colorText)
  • buttonNegative(drawableBg, colorStateListText)

Auth Slider

(color)

Auth method used to have end user acknowledge approving of a request.

  • authenticatorAuthSwitchTrackLight
  • authenticatorAuthSwitchTrackDark
  • authenticatorAuthSwitchThumbNormal
  • authenticatorAuthSwitchThumbPressed
  • authSlider(colorTrackUpper, colorTrackLower, colorThumbIdle, colorThumbPressed)
  • authSlider(colorTrackUpper, colorTrackLower, colorThumbIdle, colorThumbPressed, colotThumbIconTint)

List Headers

(visibility, color)

Headers above lists.

[View.VISIBLE, View.GONE, View.INVISIBLE]

  • authenticatorHeadersVisibility
  • listHeaders(visibility, colorBg, colorText)

Security List Icons

(visibility, Drawable)

Icons for each security factor listed in the Security view.

  • authenticatorSecurityListIconsVisibility
  • authenticatorFactorPinIcon
  • authenticatorFactorCircleIcon
  • authenticatorFactorBluetoothIcon
  • authenticatorFactorGeofencingIcon
  • authenticatorFactorFingerprintIcon
  • factorsSecurityIcons(visibility, drawableRefPinCode, drawableRefCircleCode, drawableRefGeofencing, drawableRefWearable, drawableRefFingerprintScan)
  • factorsSecurityIcons(visibility, drawablePinCode, drawableCircleCode, drawableGeofencing, drawableWearable, drawableFingerprintScan)

Help Icons

(visibility boolean)

Visibility boolean for whether to show the help menu items.

  • authenticatorShowHelpIcons
  • helpMenuItems(booleanVisibility)

PIN Code

(Drawable, color)

Auth method PIN Code.

  • authenticatorPinPadButtonBackgroundDrawableSelector
  • authenticatorPinPadButtonOverlayColorSelector
  • pinCode(drawableBg, colorText)
  • pinCode(drawableBg, colorStateListText)

Circle Code

(color)

Auth method Circle Code

  • authenticatorCirclePadMarksColor
  • authenticatorCirclePadHighlightColor
  • circleCode(colorHighlight, colorMarks)

Checking Passive Methods

(Drawable)

Icon used when checking passive methods/factors during a request.

  • authenticatorAuthRequestOngoingImageBluetooth
  • authenticatorAuthRequestOngoingImageGeofencing
  • authenticatorAuthRequestOngoingImageFingerprint
  • factorsBusyIcons(drawableGeofencing, drawableWearable, drawableFingerprintScan)
  • factorsBusyIcons(drawableRefGeofencing, drawableRefWearable, drawableRefFingerprintScan)

Settings Headers

(color)

Top layout in security views involving methods/factors.

  • settingsHeaders(colorBg, colorText)
  • settingsHeaders(colorBg, colorText)

Text Field

(color)

Basic color for EditText in default manual linking view.

  • editText(colorHint, colorText)
  • editText(colorHint, colorText)

Example: UI Customization

First override the default XML theme. Custom properties might look like the following:

<style name="CustomOverridingTheme" parent="AuthenticatorTheme">
    <item name="authenticatorColorPrimary">#00BCD4</item>
    <item name="authenticatorColorPrimaryDark">#00838F</item>
    <item name="authenticatorColorAccent">#8c9eff</item>
    <item name="authenticatorColorBackground">#a0c1bf</item>
    <item name="authenticatorColorBackgroundOverlay">#2d3d3c</item>
</style>

Then pass the customizations to the AuthenticatorConfig method:

AuthenticatorConfig config = new AuthenticatorConfig.Builder(...)
    ...
    .theme(R.style.CustomTheme)
    .build();

    AuthenticatorManager.getInstance().initialize(config);

With v4.4 and up, it is possible to provide custom properties at runtime through the new AuthenticatorTheme.Builder class that builds a theme object provided to the AuthenticatorConfig.Builder instance before initializing the SDK.

For example:

...
// Create AuthenticatorTheme through its Builder class with custom properties
AuthenticatorTheme runtimeTheme = new AuthenticatorTheme.Builder(Context)
    .appBar(Color.DKGRAY, Color.BLUE)
    .background(new ColorDrawable(Color.DKGRAY))
    ...
    .build();

// Pass it to the AuthenticatorConfig object before initializing the SDK
AuthenticatorConfig config = new AuthenticatorConfig.Builder(...)
    ...
    .theme(runtimeTheme)
    .build();

AuthenticatorManager.getInstance().initialize(config);
...

Reference the "Java" column in the table in the Properties Reference above.

SSL Pinning (Extra Security)

new AuthenticatorConfig.Builder(...)
...
.sslPinning(boolean)
...
.build();

The Authenticator SDK uses SSL for network communication to the LaunchKey Platform API to ensure secure data transmission. However, to protect against eavesdropping and ensure that man-in-the-middle attacks cannot occur over this connection, you can enable SSL pinning which will verify the hostname and SSL certificate returned from the Platform API handshake exactly matches those that are bundled in your Mobile App. If the certificate cannot be verified, all connections to the Platform API are terminated. To turn SSL pinning ON, include the .sslPinning() method in your configuration object and pass a value (boolean) of true to turn on, or false to explicitly turn it off.

Note

SSL pinning is turned OFF by default.

Warning

SSL pinning should only be enabled if you fully understand the consequences of enabling this feature as connectivity to the LaunchKey Platform API can be interrupted if SSL pinning is not properly configured.

Adding Push Notifications to Your Integration

Warning

Starting with v4.0.0, the Authenticator SDK does not handle the reception of Push Notifications directly. Instead, it requires the implementing application to handle Push Notifications and notify the Auth SDK when a new device token is generated or a payload is meant for the SDK. Scroll down to the section "Changes with v4.x" for more information.

Overview

iovation recommends adding push notifications to your integrations in order to provide a better experience for End Users. We also recommend providing a mechanism to manually check for pending Auth Requests, because push notifications depend on many interrelated systems to work, such as mobile carrier availability and performance in Google's own infrastructure, and are not guaranteed to reach the device(s).

Starting with v4.0.0, the Authenticator SDK is not handling the reception of Push Notifications directly. Instead, the implementing application must notify the Auth SDK when a new device token is generated or a payload meant for the SDK has been received. Because of that, GCM or FCM may be used in your application as long as supported by your integration.

Note

Since Google announced the deprecation of the original service, Google Cloud Messaging (GCM), we highly recommended moving to Firebase Cloud Messaging as the official replacement. You can read about the deprecation announcement and migration process here.

If for some reason your integration is still depending on GCM for the immediate future and a version of the Auth SDK earlier than v4, then the integration can still let the SDK handle GCM push notifications internally by following the steps outlined in the "Supporting GCM" section down below.

Supporting GCM (Deprecated)

The LaunchKey SDK (v3 or earlier) provides all of the classes you need to support push notifications. Follow the steps:

Update your AndroidManifest.xml file:

  1. Place the following permissions at the same level as the normal permissions:

    <!—- GCM-required package-based permissions —->
    <permission android:name="<YOUR PACKAGE>.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="**<YOUR PACKAGE>**.permission.C2D_MESSAGE" />
    <!—- All other GCM-required permissions are part of the SDK manifest and will be merged by Android —->
    
  2. Add the following to the <application> tag. Note that <YOUR PACKAGE> refers to your app's package.:

    <!-- GCM's own service that will handle upcoming push notifications -->
    <receiver
       android:name="com.google.android.gms.gcm.GcmReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="**<YOUR PACKAGE>**" />
        </intent-filter>
    </receiver>
    
    <!-- The Authenticator SDK's service to process push notification -->
    <service
        android:name="...android.authenticator.sdk.gcm.GcmNotificationService"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>
    
    <!-- The Authenticator SDK's service to handle the update of the device-level GCM token -->
    <service
        android:name="...android.authenticator.sdk.gcm.GcmInstanceIdListenerService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID"/>
        </intent-filter>
    </service>
    
    <!-- The Authenticator SDK's service to update the servers with the new GCM token -->
    <service
        android:name="...android.authenticator.sdk.gcm.GcmNotificationRegistrar"
        android:exported="false">
    </service>
    
    <!-- Google Play Services' required version declaration -->
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
    

Generate a server API key and a google-service.json file for your app:

  1. Go to the Google Developers Console at https://console.developers.google.com/.

  2. Open your Google Maps support project. This may be the same project that you use for push notifications.

  3. Open Library under API Manager and make sure that Google Maps for Android v2 is enabled.

  4. Under Credentials, create a new Android key and follow the instructions.

  5. Add the new key to the AndroidManifest.xml file. Place it under a <meta-data element with the android:name property set to com.google.android.geo.API_KEY. Write the key to an android:value property, for example:

    <!--Value API_KEY_HERE will be replaced with the actual key just generated -->
    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="API_KEY_HERE"
    />
    

Changes with v4.x

Check the Migrating section when moving from the SDK v3.x to the newer v4.x to keep your application fully functional. You can also reference the sample app in the GitHub repository.

Migrating

  • Implement your own push notification classes to register the device with the GCM service, update its token, and receive push notifications. When the device token is refreshed or a new notification is received, it needs to be passed back to the Auth SDK via AuthenticatorManager.updatePushNotificationToken(...) and AuthenticatorManager.onPushNotification(...). This allows for more flexibility for existing applications and newer (or older) implementations of the push notifications classes. You can reference the sample app in the public repo of the Authenticator SDK for Android on GitHub to implement the same GCM classes in your application for it to work on your first run.
  • Remove all references to the now-deprecated T-OTPs/Codes.
  • Remove inherence of AuthenticatorApplication if used and subclass Android's own base Application class.
  • Remove all references to AuthenticatorConfig.Builder.endpoint(...) and AuthenticatorConfig.Builder.sslCert(...).

What's new with v4.0

  • New DeviceKeyPairGeneratedEventCallback to keep track of when the device is ready for setup. AuthenticatorManager will automatically coordinate around this event when linking a device via .linkDevice(...) or default linking views.
  • New style properties authenticatorColorNegativeWidgetText and authenticatorColorNegativeWidgetBackground to override the default color of widgets (and text if it has any) related to negative actions (Unlinking in default Devices view, removing a factor, etc.).

What's new with v4.1

  • Added support for OpenStreetMap (OSM) along with Google Maps. OSM is the default implementation, unless dependencies for Google Maps are found as part of the build. Add this line to your app's build.gradle file:

    ...
    compile 'org.osmdroid:osmdroid-android:5.6.5@aar'               // Add to use OSM as the map view when not utilizing Google Maps
    ...
    
  • Added support for device-only location services, optionally making use of Google's own Location Services via Play Services whenever possible (if dependencies include that set of APIs).

Warning

If using Google Maps, remember to provide a valid Google Maps key via AndroidManifest.xml. You may also be subject to Google's own terms of services when using their service(s).

Updated list of dependencies in the app's build.gradle file:

...
compile 'com.android.support:support-v4:23.4.0'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.okhttp3:okhttp:3.3.1'
compile 'org.bitbucket.b_c:jose4j:0.4.4'
compile 'com.google.android.gms:play-services-base:8.3.0'
compile 'com.google.android.gms:play-services-location:8.3.0'   // Optional for better location tracking
compile 'com.google.android.gms:play-services-maps:8.3.0'       // Optional to use Google Maps in the map view when setting a geo-fence
compile 'com.google.android.gms:play-services-gcm:8.3.0'        // Used only in the parent app to support push notifications
compile 'com.google.android.gms:play-services-wearable:8.3.0'   // Optional for Android Wear devices to show as security factors
compile 'com.getpebble:pebblekit:3.0.0'                         // Optional for now-deprecated Pebble devices to show as security factors
compile 'org.osmdroid:osmdroid-android:5.6.5@aar'               // Add to use OSM as the map view when not utilizing Google Maps
...
// If supporting FCM as the Push Notification service, reference library and version
// requirements in "Supporting FCM" under
// "Adding Push Notifications to Your Integration."

What's new with v4.2

  • Knowledge factors are not mutually exclusive anymore. The behavior changed to support more than one knowledge factor at a time if the End User decides to set more than one up.
  • Added support for Local Auth Requests where the app is allowed to generate a localized Auth Request limited to that authenticator without relying on the LaunchKey Service. Keep the following in mind when making use of the new LocalAuthManager class:
    • Supports offline authentication. For example, it can be used to authenticate an End User before displaying sensitive content.
    • Allows the End User to set up Security factors and authenticate through Local Auth Requests even when unlinked if the new config flag allowSecurityChangesWhenUnlinked(boolean) is set to true in the AuthenticatorConfig object when initializing the SDK.
    • Titles of Local Auth Requests can be set to a custom title through LocalAuthManager.setTitle(String). null can be passed if the default title is meant to be shown instead.
    • Expiration of Local Auth Requests can be set to a custom value but must be within two and five minutes, two minutes being the default value if not specified through LocalAuthManager.setExpireIn(seconds).
    • LocalAuthManager introduces two new event callbacks: GetLocalAuthEventCallback and LocalAuthResponseEventCallback.
    • When generating a Local Auth Request, a Policy object must be passed along to set the requirements for that request (built through the new PolicyFactory class) and will let implementors build it matching what can be possible with the LaunchKey Service through the Service SDKs.
    • Can only be used when there's at least one factor set up, otherwise the new NoSecurityFactorsError object is propagated via GetLocalAuthEventCallback.

For example:

...
// Right before initializing the SDK, allow end users to set Security factors when unlinked
// For the most part this is not necessary unless it will always be an offline-only
//  implementation. Otherwise rely on linking the device and make use of this
//  feature in scenarios like full isolation of Internet connectivity.
AuthenticatorConfig config = new AuthenticatorConfig.Builder(Context, authSdkKey)
        ...
        .allowSecurityChangesWhenUnlinked(true)
        .build();
...

// Register for both related events
GetLocalAuthEventCallback onLocalAuth = new GetLocalAuthEventCallback() {

    @Override
    public void onEventResult(boolean ok, BaseError e, LocalAuthRequest lar) {

        if (!ok) {

            // Handle error based on type of BaseError
        }
    }
};

LocalAuthResponseEventCallback onLocalResponse = new LocalAuthResponseEventCallback() {

    @Override
    public void onEventResult(boolean ok, BaseError e, Boolean approved) {

        if (ok && approved) {

            // Load up content if successful and approved.
            // Make sure content is removed off the View(s)
            //  and memory as soon as the Activity's/Fragment's
            //  onPause() lifecycle method is called to protect
            //  the content until once again authenticated
        }
    }
};

// Get LocalAuthManager instance to register event callbacks
LocalAuthManager localAuthManager = LocalAuthManager.getInstance();
localAuthManager.registerForEvents(onLocalAuth, onLocalResponse);

// Build a Policy object to generate a Local Auth Request requiring at least one factor
Policy policy = new PolicyFactory().getPolicy(1);

boolean generated = localAuthManager.authenticateUser(policy);

if (generated) {
    // Bring up AuthRequestFragment to authenticate the End User
} else {
    // Let GetLocalAuthEventCallback handle the error
}

What's new with v4.3

  • Collection of anonymous metrics to better support the service and understand the behavior of the Authenticator SDK in order to make improvements in newer versions.
  • Added a public AuthenticatorManager#sendMetrics(...) method to help implementers provide collected metrics to our service on the fly whenever necessary.

What's new with v4.4

  • Added support for dynamic theming along with new customizable properties. The SDK will continue to support the XML pattern, but at runtime, implementing apps can now provide Drawable, colors, and other instantiated resources to methods of the new AuthenticatorTheme.Builder class to return a built AuthenticatorTheme object. The custom-built theme object then can be passed to the AuthenticatorConfig.Builder object before initializing the SDK. For more details on customizable properties, check the Customizing the User Interface section above.

Best practices

  • Error handling

Most, if not all, errors returned by the Authenticator SDK are subclasses of the BaseError class. Here's a list of all errors:

BaseError
Base class for errors returned by operations in the Authenticator SDK. Will have a simple code and message. All other error types are subclasses of BaseError.
ApiError
Error returned by a response from the LaunchKey service when a request is unsuccessful It has API-specific errors and the code can be returned as an integer through its getCodeInt(). The integer returned by the aforementioned method can be directly compared against all errors publicly defined by the ApiError class. Most errors defined should not happen, but it can shed more light into a particular error returned through its message and API-specific code.
CommunicationError
Error returned when there was a problem attempting to communicate with the LaunchKey service.
DeviceAlreadyLinkedError
Error returned when attempting to link an authenticator that is already linked.
DeviceNotFoundError
While unlikely, this error is returned when requesting the DeviceManager class to unlink an authenticator with its Device object representation that matches no linked authenticator in the LaunchKey service for the current user.
DeviceNotLinkedError
Error returned when attempting to perform an action that requires a linked authenticator and the current authenticator is unlinked.
ExpiredAuthRequestError
Error returned when the End User is attempting to respond to an Auth Request that has expired.
MalformedLinkingCodeError
Error returned when attempting to link an authenticator with a linking code in an invalid format (null, empty, invalid characters, unexpected length).
NoInternetConnectivityError
Error returned when the SDK detects no Internet connectivity to the LaunchKey service.
RequestArgumentError
Error returned by a function when an argument passed to a method in the SDK is invalid if not covered by one of the relevant errors above already.
UnexpectedCertificateError
Error returned when attempting to connect to the LaunchKey service and SSL Pinning is failing (if explicitly enabled) due to an unexpected CA certificate seemingly representing the API. This error may point out an attempt of a man-in-the-middle attack.
  • Display an active Session after authorizing an Auth Request

There's no direct correlation between an Auth Request and an active Session. It is up to the Subscriber's service to handle the response of Auth Requests and then request the LaunchKey API to start a Session if desired. There is a bit of a delay between the End User responding to an Auth Request and your service as an implementer handling the response, so it is recommended adding a bit of a delay of a few seconds, say, three, to refresh the list of active Sessions after responding to Auth Requests.

  • Updating device token for Push Notifications

Always make sure to update a new/changed device token meant for Push Notifications in order for the LaunchKey service to keep an updated record and notify the End Users of pending Auth Requests.

  • Keep the Authenticator SDK up to date

Updates will include improvements, security patches, and/or new features that will enhance the user experience of End Users if the release increases its minor version.

Should a major version be released, keep an eye on the docs on how to migrate over to rely on the latest.

  • Keep SSL Pinning enabled

SSL Pinning could prove troublesome if proxies are inherent to an application or service but can enhance the security of a product by preventing Man-in-the-Middle attacks.

  • Do NOT allow restore from backups

It is recommended to avoid issues and keep the experience stable. One of the issues with allowing backups would be the device name meant for a different device that may not even match the new device and will confuse End Users about which device is potentially responding to Auth Requests.

  • Portrait-only Activities

The Authenticator SDK currently supports portrait as the sole orientation for Activity instances in order for the UI to stay consistent when interacting with security factors during setup or in the middle of an Auth Request. Support for landscape orientation may come in the future but is NOT part of the product roadmap at this point.

  • Listen for important events

In main views, keep listening for major events like a new Auth Request, the device being linked or even unlinked, etc. Register listeners through one or more Manager objects detailed in the document to listen for the main events in order to keep the UI, and the End Users, updated.

  • Always provide ability to manually refresh data

While we rely heavily on Push Notifications to notify the End User of pending Auth Requests in a timely manner, it is important to remember that is still an external service outside the scope of the LaunchKey service, and delays or drops of Push Notifications can happen at times. Allowing the End User to check pending Auth Requests, refresh the list of active Sessions or linked authenticators will come a long way in these few instances.

  • Issues with an authenticator communicating with your service

Always check the LaunchKey Admin Center and ensure all keys are matching the ones on your end--including the Authenticator SDK key fed to a AuthenticatorConfig object when initializing the SDK upon app start.

  • Protect users and sensitive data on-screen

Make sure your own Views are prevented from showing sensitive data in previews of the screen when switching apps or attempting to take screenshots. The Android OS should prevent this from happening when enabling FLAG_SECURE at runtime.

When there is an app overlaying everything else on-screen that could potentially expose users to tap-jacking attacks, disable all interactions with important views. Mostly an issue in older versions of Android where overlaying applications are not actively exposed. For this, check the Security section in the official Android documentation of the class View.

  • Require security factors at all times

If you're certain your Service will always require at least one security factor, then it is possible for the implementing app to be aware of how many factors have been set and have its own UI update and guide the user towards the Security view to set one up.

The SecurityService class can be interacted with through its instance and require an asynchronous update that will return a list of SecurityFactor objects with info on the security factors.

Example:

SecurityService.getInstance(Context).getStatus(new SecurityService.SecurityStatusListener() {
        @Override
        public void onSecurityStatusUpdate(
                boolean ok, List<SecurityFactor> list, BaseError e) {

            // If OK, check list and update UI as necessary
        }
    });

User Contributed

LaunchKey links to user contributed code as a resource to its community. LaunchKey does not in any way guarantee or warrant the quality and security of these code bases. User contributed code is supported by the creators. If you do find a link from the site to user contributed code that is malicious or inappropriate in any way, please report that link to LaunchKey immediately and we will investigate the claim. Submit any issue to LaunchKey support at https://launchkey.com./support. ×