Skip to content

nevissecurity/nevis-mobile-authentication-sdk-example-app-android

Repository files navigation

Nevis Logo

Nevis Mobile Authentication SDK Android Example App

Main Branch Commit Verify Pull Request

This repository contains the example app demonstrating how to use the Nevis Mobile Authentication SDK in an Android mobile application. The Nevis Mobile Authentication SDK allows you to integrate passwordless authentication to your existing mobile app, backed by the FIDO UAF 1.1 Standard.

Some SDK features demonstrated in this example app are:

  • Using the SDK with the Nevis Authentication Cloud
  • Registering with QR code & app link URIs
  • Simulating in-band authentication after registration
  • Deregistering a registered account
  • Changing the PIN of the PIN authenticator
  • Changing the device information

Please note that the example app only demonstrates a subset of the available SDK features. The main purpose is to demonstrate how the SDK can be used, not to cover all supported scenarios.

Getting Started

Before you start compiling and using the example applications please ensure you have the following ready:

Server-side Environment

  • In case you are planning to use Authentication Cloud you need an Authentication Cloud instance provided by Nevis and an access key to use it.
  • In case you are planning to use an Identity Suite environment ensure that the environment is up and running and you have all necessary URLs and permissions to access it.

Development Setup

  • Android 6 or later, with API level 23
  • Android 10 or later, with API level 29, for the biometric authenticator to work
  • Android 11 or later, with API level 30, for the device passcode authenticator to work
  • Android Studio 3.5.1 or later
  • JDK 11
  • Gradle 7.2 or later

Github Account

SDK dependency used by this project are provided via GitHub Packages that is used as a Maven repository. To access GitHub Packages a valid GitHub account and a Personal Access Token is needed. If you have not done it yet, please create a Personal Access Token with Packages Read permission. Once the Personal Access Token is created add the following properties to your global gradle.properties file (e.g.: /Users/<YOUR USERNAME>/.gradle/gradle.properties).

GITHUB_USERNAME=<YOUR USERNAME>
GITHUB_PERSONAL_ACCESS_TOKEN=<YOUR PERSONAL ACCESS TOKEN>

Open the Project

Clone the example application GitHub repository and open it with Android Studio.

Configuration

The example applications support two kinds of configuration: authenticationCloud and identitySuite. The following chapters describes how to change the base configuration to match your environment. The configuration could be changed by modifying the ApplicationModule file which describes the dependency injection related configuration using the Dagger Hilt library and the AndroidManifest.xml.

Note

Only build-time configuration change is supported.

Authentication Cloud Configuration

Before being able to use the example application with your Authentication Cloud instance, you will need to update the configuration with the right host information.

Edit the ApplicationModule file and replace the host name information with your Authentication Cloud instance in method provideAuthenticationCloudConfiguration.

Identity Suite Configuration

If you want to use identitySuite environment modify the configuration in method provideIdentitySuiteConfiguration and modify this part:

@Provides
@Singleton
fun provideConfigurationProvider(application: Application): ConfigurationProvider =
    ConfigurationProviderImpl(
        Environment.AUTHENTICATION_CLOUD,
        provideAuthenticationCloudConfiguration(application)
    )

to

@Provides
@Singleton
fun provideConfigurationProvider(application: Application): ConfigurationProvider =
    ConfigurationProviderImpl(
        Environment.IDENTITY_SUITE,
        provideIdentitySuiteConfiguration(application)
    )

Android Manifest XML

The example applications handle deep links those contain a valid dispatchTokenResponse query parameter of an out-of-band operation. The related configuration located in the AndroidManifest.xml for MainActivity with action android.intent.action.VIEW.

Deep links

Change the myaccessapp scheme value in the following intent-filter with the right scheme information of your environment.

<intent-filter>
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />

    <data android:scheme="myaccessapp" />
</intent-filter>

Note

For more information about deep links, visit the official Android guide.

Facet ID

The FIDO server (i.e. nevisFIDO) must be configured with the facet ID(s) of your application(s). If the facet ID of your application is not referenced by the nevisFIDO configuration, the operations will fail with an UNTRUSTED_FACET_ID error.

By default the SDK assumes that the facet ID to be used is the one that follows the FIDO UAF 1.1 Specifications that is the facet ID on Android should follow the android:apk-key-hash:HASH_VALUE format, where the HASH_VALUE is Base64 encoded SHA-256 hash of the APK signing certificate.

The facet ID can be calculated using the following code snippet:

import android.content.pm.PackageInfo
import android.util.Base64
import java.io.ByteArrayInputStream
import java.security.MessageDigest
import java.security.cert.CertificateFactory
object FacetIdCalculator {
	fun calculateFacetId(packageInfo: PackageInfo): String {
		val byteArrayInputStream = ByteArrayInputStream(packageInfo.signingInfo.signingCertificateHistory[0].toByteArray())
		val certificate = CertificateFactory.getInstance("X509").generateCertificate(byteArrayInputStream)
		val digest = MessageDigest.getInstance("SHA-256")
		return "android:apk-key-hash" + Base64.encodeToString(digest.digest(certificate.encoded), Base64.NO_PADDING or Base64.NO_WRAP)
	}
}

Note

An alternative way to set a constant Facet ID is to call facetId(String facetId) method of ch.nevis.mobile.sdk.api.Configuration.Builder in methods provideAuthenticationCloudConfiguration and provideIdentitySuiteConfiguration in ApplicationModule file.

The value of the facet ID depends on the certificate used to build the application, which can change during the development, that is why this method has been introduced: by providing a constant facet ID and having it referenced in the server server configuration, temporary changes in the APK signing certificate do not require changes in the backend.

This method must be used for development scenarios only. For production code do not invoke this method and configure the backend with the facet ID that can be calculated with the code snippet above. See the chapter Application Facet ID and the nevisFIDO Backend Configuration of the SDK reference guide for more details.

Build & run

Now you are ready to build and run the example app by choosing Run > Run 'app' from Android Studio's menu or by clicking the Run button in your project’s toolbar.

If you want to build and install the application from the command-line from *nix systems, you can execute the following:

$ cd <example repository root>
$ ./gradlew installDebug

It will build the application and install it if there is an emulator running in your machine, or if a physical device with debug enabled is connected to your machine.

Try it out

Now that the Android example app is up and running, it's time to try it out!

Check the Using the Example Application of our quickstart guide for usage instructions.

Used Components, Concepts

Android Jetpack Navigation

The navigation between the views/fragments are handled and described using the Android Jetpack Navigation component. The Gradle plugin Safe Args is also used to pass data to navigation destination fragments with type safety.

Dagger Hilt

Dependency Injection framework Dagger Hilt is used to inject an SDK instance and logger, view model, operation and delegate instances where necessary.

MVVM

As this is the suggested and supported application architecture, MVVM is used. Each view is implemented as a androidx.fragment.app.Fragment and each view has a androidx.lifecycle.ViewModel implementation if necessary.

Kotlin

The application is written in Kotlin.

Timber

Timber is used to display logs describing the steps of the operations. The logs are presented to help understand the flow of the operations managed by the SDK.

Integration Notes

In this section you can find hints about how the Nevis Mobile Authentication SDK is integrated into the example app.

  • All SDK invocation is implemented in the corresponding view model class.
  • All SDK specific user interaction related protocol implementation can be found in the interaction package.

Initialization

The HomeViewModel class is responsible for creating and initializing a MobileAuthenticationClient instance which is the entry point to the SDK. Later this instance can be used to start the different operations.
The initialized MobileAuthenticationClient instance can be accessed via ClientProviderImpl.

Registration

Before being able to authenticate using the Nevis Mobile Authentication SDK, go through the registration process. Depending on the use-case, there are two types of registration: in-app registration and out-of-band registration.

In-app registration

If the application is using a backend using the Nevis Authentication Cloud, the AuthCloudRegistrationViewModel class will be used by passing the enrollment response or an appLinkUri.

When the backend used by the application does not use the Nevis Authentication Cloud the name of the user to be registered is passed to the UserNamePasswordLoginViewModel class. If authorization is required by the backend to register, provide an AuthorizationProvider.
In the example app a CookieAuthorizationProvider is created from the cookies (see UserNamePasswordLoginViewModel) obtained from a login Retrofit call.

Out-of-band registration

When the registration is initiated in another device or application, the information required to process the operation is transmitted through a QR code or a link. After the payload obtained from the QR code or the link is decoded and processed by HomeViewModel or QrReaderViewModel which are both sub-classes of OutOfBandViewModel.

Authentication

Using the authentication operation, you can verify the identity of the user using an already registered authenticator. Depending on the use-case, there are two types of authentication: in-app authentication and out-of-band authentication.

In-app authentication

For the application to trigger the authentication, the name of the user is provided to the SelectAccountViewModel class.

Out-of-band authentication

When the authentication is initiated in another device or application, the information required to process the operation is transmitted through a QR code or a link. After the payload obtained from the QR code or the link is decoded and processed by HomeViewModel or QrReaderViewModel which are both sub-classes of OutOfBandViewModel.

Transaction confirmation

There are cases when specific information is to be presented to the user during the user verification process, known as transaction confirmation. The AuthenticatorSelectionContext and the AccountSelectionContext contain a byte array with the information. In the example app it is handled in the AccountSelectorImpl and TransactionConfirmationViewModel classes.

Deregistration

The HomeViewModel class is responsible for deregistering either a user or all of the registered users from the device.

Other operations

Change PIN

The change PIN operation is implemented in the HomeViewModel, SelectAccountViewModel and PinViewModel classes with which you can modify the PIN of a registered PIN authenticator for a given user.

Change device information

During registration, the device information can be provided that contains the name identifying your device, and also the Firebase Cloud Messaging registration token. Updating both the name and the token is implemented in the ChangeDeviceInformationViewModel class.

© 2023 made with ❤ by Nevis