Mobile authentication
- Introduction
- What to set up
- Requirements for mobile authentication
- Enrollment
- Handling push notifications
- Types of mobile authentication requests
Introduction
The Onegini Mobile Security Platform offers a mobile authentication mechanism in a user friendly and secure way. You can take advantage of the mobile authentication to add a second factor authentication for your product, that can be used to improve security of selected actions like logging into your website or accepting a transaction payment.
What to set up
As a medium to send push messages for mobile authentication Google Cloud Messaging (GCM) is used so you have to set it up:
- in a Google Console,
- on the Token Server,
- within your Android application.
To set up GCM in the Google Console and the Token Server please follow steps described in google documentation and the Token Server's documentation.
Requirements for mobile authentication
In order to use the mobile authentication the device has to support Google Play Services. It's a responsibility of the app's developer to check if push notifications are supported on the device. Once push notifications are available on the device the app should fetch the registration id, which is used as a push token during the mobile authentication enrollment. Once again please refer to the google documentation on how to obtain this registration id. In order to use mobile fingerprint authentication you need to make sure that device has a fingerprint scanner and fulfills all requirements that are listed here.
Enrollment
After you've set up the GCM, you need to perform an enrollment for authenticated user in order to register him for the mobile authentication. The user can be enrolled on only one application instance at a time. If the user has two mobile devices on which the application is installed, the user can only enroll for mobile authentication on one of these devices. It's your application responsibility to handle all of the GCM communication including fetching the registration id. The reason why this responsibility is in the app is that one app can only have one registration id. This allows the app to support more push messaging features besides the mobile authentication provider by the SDK.
Example code to initialize mobile authentication enrollment for currently authenticated user
final UserClient userClient = OneginiSDK.getOneginiClient(context).getUserClient();
// should be triggered for authentiated user only or an error will be returned
userClient.enrollUserForMobileAuthentication("myRegistrationId", new OneginiMobileAuthenticationEnrollmentHandler() {
@Override
void onSuccess() {
// Method called when mobile authentication was successfully enrolled.
setMobileAuthenticationEnabled(true);
}
@Override
public void onError(final OneginiMobileAuthenticationEnrollmentError error) {
@OneginiMobileAuthenticationEnrollmentError.MobileAuthenticationEnrollmentErrorType final int errorType = error.getErrorType();
// This method is called when a mobile authentication enrollment error occurs, for example when the device is deregistered
if (errorType == OneginiMobileAuthenticationEnrollmentError.DEVICE_DEREGISTERED) {
new DeregistrationUtil(GCMInstanceIDListenerService.this).onDeviceDeregistered();
}
setMobileAuthenticationEnabled(false);
}
private void setMobileAuthenticationEnabled(final boolean isEnabled) {
UserProfile authenticatedUserProfile = OneginiSDK.getOneginiClient(this).getUserClient().getAuthenticatedUserProfile();
if (authenticatedUserProfile == null) {
return;
}
final SettingsStorage settingsStorage = new SettingsStorage(GCMInstanceIDListenerService.this);
settingsStorage.setMobileAuthenticationEnabled(authenticatedUserProfile, isEnabled);
}
);
If you want to use mobile fingerprint authentication you need to provide an instance of OneginiMobileAuthenticationFingerprintRequestHandler
with the
OneginiClientBuilder
using setMobileAuthenticationFingerprintRequestHandler()
method. You also need to register a fingerprint authenticator to be able to use it.
Example code for registering a fingerprint authentication
OneginiAuthenticator fingerprintAuthenticator;
// to get the fingerprint authenticator
final Set<OneginiAuthenticator> notRegisteredAuthenticators = OneginiSDK.getOneginiClient(context).getUserClient().getNotRegisteredAuthenticators(userProfile);
for (final OneginiAuthenticator auth : notRegisteredAuthenticators) {
if (auth.getType() == OneginiAuthenticator.FINGERPRINT) {
// the fingerprint authenticator is available for registration
fingerprintAuthenticator = auth;
}
}
// fingerprint authentication is not always available
if (fingerprintAuthenticator == null) {
return;
}
//to register the authenticator
OneginiSDK.getOneginiClient(context).getUserClient().registerAuthenticator(fingerprintAuthenticator, new OneginiAuthenticatorRegistrationHandler() {
@Override
public void onSuccess() {
// successfully registered authenticator
}
@Override
public void onError(final OneginiAuthenticatorRegistrationError oneginiAuthenticatorRegistrationError) {
// handle different errors, below we mapped two of the possible errors that can occur
@OneginiAuthenticatorRegistrationError.AuthenticatorRegistrationErrorType int errorType = error.getErrorType();
if (errorType == OneginiChangePinError.USER_DEREGISTERED) {
UserProfile authenticatedUserProfile = OneginiSDK.getOneginiClient(SettingsAuthenticatorsActivity.this).getUserClient().getAuthenticatedUserProfile();
if (authenticatedUserProfile == null) {
return;
}
new DeregistrationUtil(SettingsAuthenticatorsActivity.this).onUserDeregistered(authenticatedUserProfile);
} else if (errorType == OneginiChangePinError.DEVICE_DEREGISTERED) {
new DeregistrationUtil(SettingsAuthenticatorsActivity.this).onDeviceDeregistered();
}
}
});
Handling push notifications
Push notifications are handled by the application that delegates the handling of the push notification to the SDK. The SDK will determine if it should do
something with the push notification or not before handling it. This allows the app to support multiple types of push notifications next to the mobile
authentication push notification. You can trigger it with handleMobileAuthenticationRequest()
on the UserClient
instance.
public void handleMobileAuthenticationRequest(final Bundle pushMessage, final OneginiMobileAuthenticationHandler mobileAuthenticationHandler);
Then the SDK will use OneginiMobileAuthenticationHandler
to perform the request and end in one of the two methods of OneginiMobileAuthenticationHandler
:
Mobile Authentication was successful
void onSuccess();
Mobile Authentication failed due to an
error
void onError(OneginiMobileAuthenticationError error);
Please note, that the user has an ability to deny incoming mobile authentication request. In such case the
onError
method will be called with anACTION_CANCELED
error type.
For more info on error handling see the error handling topic guide.
Example code push notification handling
@Override
protected void onHandleIntent(final Intent intent) {
final Bundle extras = intent.getExtras();
if (!extras.isEmpty()) {
OneginiSDK.getOneginiClient(this).getUserClient().handleMobileAuthenticationRequest(extras, new OneginiMobileAuthenticationHandler() {
@Override
public void onSuccess() {
// Method called when mobile authentication request was successful.
}
@Override
public void onError(final OneginiMobileAuthenticationError oneginiMobileAuthenticationError) {
Toast.makeText(GCMListenerService.this, oneginiMobileAuthenticationError.getErrorDescription(), Toast.LENGTH_SHORT).show();
@OneginiMobileAuthenticationError.MobileAuthenticationEnrollmentErrorType final int errorType = oneginiMobileAuthenticationError.getErrorType();
if (errorType == OneginiMobileAuthenticationError.USER_DEREGISTERED) {
// the user was deregister, for example he provided a wrong PIN for too many times. You can handle the deregistration here, but since this application
// supports multiple profiles we handle it when the user tries to login the next time because we don't know which user profile was deregistered at
// this point.
} else if (errorType == OneginiMobileAuthenticationError.DEVICE_DEREGISTERED) {
new DeregistrationUtil(getApplicationContext()).onDeviceDeregistered();
}
}
});
}
}
As you can see from example above when user got deregistered an error is reported to the app through onError
method. To enable mobile authentication for that
user he needs to register and enroll once again.
Types of mobile authentication requests
You can configure different mobile authentication types in the Token Server mobile authentication configuration. For every type you can choose between different methods of authentication. These are: Push, Push with PIN, Push with fingerprint and Push with FIDO. The types of for mobile authentication must be configured on the Token Server first before you can use them. You can define multiple types with the same authentication method.
Push
The first type of mobile authentication request, the most simple one, is Push. In this type user have possibility to simply accept or deny request. To
support the Push type in your app you need to implement OneginiMobileAuthenticationRequestHandler
interface and set its instance during the SDK
initialization step by calling setMobileAuthenticationRequestHandler(OneginiMobileAuthenticationRequestHandler handler)
method on OneginiClientBuilder
.
Then you need to handle all interface methods in order to show/hide user interface with (for example) buttons allowing to accept or deny request.
Example how to set OneginiMobileAuthenticationRequestHandler
new OneginiClientBuilder(applicationContext, createPinRequestHandler, pinAuthenticationRequestHandler)
.setMobileAuthenticationRequestHandler(new MobileAuthenticationRequestHandler(applicationContext))
.build();
Example how to implement OneginiMobileAuthenticationRequestHandler
public class MobileAuthenticationRequestHandler implements OneginiMobileAuthenticationRequestHandler {
public static OneginiAcceptDenyCallback CALLBACK;
private final Context context;
public MobileAuthenticationRequestHandler(final Context context) {
this.context = context;
}
@Override
public void startAuthentication(final OneginiMobileAuthenticationRequest oneginiMobileAuthenticationRequest,
final OneginiAcceptDenyCallback oneginiAcceptDenyCallback) {
CALLBACK = oneginiAcceptDenyCallback;
openActivity(oneginiMobileAuthenticationRequest.getUserProfile().getProfileId(), oneginiMobileAuthenticationRequest.getMessage());
}
@Override
public void finishAuthentication() {
closeActivity();
}
private void openActivity(final String profileId, final String message) {
final Intent intent = new Intent(context, MobileAuthenticationActivity.class);
intent.putExtra(MobileAuthenticationActivity.EXTRA_COMMAND, MobileAuthenticationActivity.COMMAND_START);
intent.putExtra(MobileAuthenticationActivity.EXTRA_PROFILE_ID, profileId);
intent.putExtra(MobileAuthenticationActivity.EXTRA_MESSAGE, message);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
private void closeActivity() {
final Intent intent = new Intent(context, MobileAuthenticationActivity.class);
intent.putExtra(MobileAuthenticationActivity.EXTRA_COMMAND, MobileAuthenticationActivity.COMMAND_FINISH);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
You need to implement both startAuthentication
and finishAuthentication
methods:
startAuthentication(final OneginiMobileAuthenticationRequest oneginiMobileAuthenticationRequest, final OneginiAcceptDenyCallback oneginiAcceptDenyCallback)
is called when new mobile authentication request is received. First parameter isOneginiMobileAuthenticationRequest
object which contains message you should present to the user and UserProfile object that specifies request's receiver. The Second parameter is a callback object that you should use when user accepts or denies the request, by callingacceptAuthenticationRequest
ordenyAuthenticationRequest
respectively.finishAuthentication
method is called after end of processing the user response to the request.
Push with PIN
The Second type of mobile authentication request is Push with PIN. In this type the user also have a possibility to accept or deny request. Comparing to
simple Push the Push with PIN requires the user to enter his PIN in order to successfully accept the mobile authentication request. To support
Push with PIN type you need to implement MobileAuthenticationPinRequestHandler
interface and set its instance during SDK initialization step by
calling setMobileAuthenticationPinRequestHandler(MobileAuthenticationPinRequestHandler handler)
method on OneginiClientBuilder
. You also need to handle all
interface methods in order to show/hide user interface with a PIN input and buttons allowing to accept or deny request.
Example how to implement OneginiMobileAuthenticationPinRequestHandler
public class MobileAuthenticationPinRequestHandler implements OneginiMobileAuthenticationPinRequestHandler {
public static OneginiPinCallback CALLBACK;
private final Context context;
private String message;
private String userProfileId;
private int failedAttemptsCount;
private int maxAttemptsCount;
public MobileAuthenticationPinRequestHandler(final Context context) {
this.context = context;
}
@Override
public void startAuthentication(final OneginiMobileAuthenticationRequest oneginiMobileAuthenticationRequest, final OneginiPinCallback oneginiPinCallback, final AuthenticationAttemptCounter attemptCounter) {
CALLBACK = oneginiPinCallback;
message = oneginiMobileAuthenticationRequest.getMessage();
userProfileId = oneginiMobileAuthenticationRequest.getUserProfile().getProfileId();
failedAttemptsCount = maxAttemptsCount = 0;
startActivity();
}
@Override
public void onNextAuthenticationAttempt(final AuthenticationAttemptCounter attemptCounter) {
this.failedAttemptsCount = attemptCounter.getFailedAttempts();
this.maxAttemptsCount = attemptCounter.getMaxAttempts();
startActivity();
}
@Override
public void finishAuthentication() {
closeActivity();
}
private void startActivity() {
final Intent intent = new Intent(context, MobileAuthenticationPinActivity.class);
intent.putExtra(MobileAuthenticationPinActivity.EXTRA_COMMAND, MobileAuthenticationPinActivity.COMMAND_START);
intent.putExtra(MobileAuthenticationPinActivity.EXTRA_MESSAGE, message);
intent.putExtra(MobileAuthenticationPinActivity.EXTRA_PROFILE_ID, userProfileId);
intent.putExtra(MobileAuthenticationPinActivity.EXTRA_FAILED_ATTEMPTS_COUNT, failedAttemptsCount);
intent.putExtra(MobileAuthenticationPinActivity.EXTRA_MAX_FAILED_ATTEMPTS, maxAttemptsCount);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
private void closeActivity() {
final Intent intent = new Intent(context, MobileAuthenticationPinActivity.class);
intent.putExtra(MobileAuthenticationPinActivity.EXTRA_COMMAND, MobileAuthenticationPinActivity.COMMAND_FINISH);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
You need to implement startAuthentication
, onNextAuthenticationAttempt
and finishAuthentication
methods:
startAuthentication(final OneginiMobileAuthenticationRequest oneginiMobileAuthenticationRequest, final OneginiPinCallback oneginiPinCallback, final AuthenticationAttemptCounter attemptCounter)
the app receives new mobile authentication request. First parameter isOneginiMobileAuthenticationRequest
object which contains message you should present to the end user, UserProfile object that specifies request's receiver. Second parameter is a callback object you should use when user accepts or denies incoming request by calling:acceptAuthenticationRequest(pinEnteredByUser)
ordenyAuthenticationRequest
respectively. Third parameter isAuthenticationAttemptCounter
that holds information about failed, remaining and max PIN attempts.onNextAuthenticationAttempt(final AuthenticationAttemptCounter attemptCounter)
is called when user entered wrong pin. TheattemptCounter
param object gives you the information about failed attempts count viagetFailedAttempts()
method indicating how many times wrong PIN was entered during current authentication attempt. Same way you can get max attempts withgetMaxAttempts()
method and remaining attempts withgetRemainingAttempts()
. You can display those values to the user.finishAuthentication
is called after end of processing the user response to the request.
Push with fingerprint
The third type of mobile authentication request is Push with fingerprint. In this type the user also have a possibility to accept or deny request. The Push with
fingerprint requires the user to scan his fingerprint in order to successfully accept the mobile authentication request. To support Push with fingerprint type
you need to implement OneginiMobileAuthenticationFingerprintRequestHandler
interface and set its instance during SDK initialization step by calling
setMobileAuthenticationFingerprintRequestHandler(OneginiMobileAuthenticationFingerprintRequestHandler mobileAuthenticationFingerprintRequestHandler)
method on
OneginiClientBuilder
. You also need to handle all interface methods in order to show/hide user interface with a fingerprint input and buttons allowing to
accept or deny request as well as fallback to PIN.
Example how to implement OneginiMobileAuthenticationFingerprintRequestHandler
public class MobileAuthenticationFingerprintRequestHandler implements OneginiMobileAuthenticationFingerprintRequestHandler {
public static OneginiFingerprintCallback fingerprintCallback;
private final Context context;
public MobileAuthenticationFingerprintRequestHandler(final Context context) {
this.context = context;
}
@Override
public void startAuthentication(final OneginiMobileAuthenticationRequest oneginiMobileAuthenticationRequest, final OneginiFingerprintCallback oneginiFingerprintCallback) {
fingerprintCallback = oneginiFingerprintCallback;
startFingerprintActivity(MSG_EXTRA_ASK_TO_ACCEPT_OR_DENY);
}
@Override
public void onNextAuthenticationAttempt() {
startFingerprintActivity(MSG_EXTRA_RECEIVED_FINGERPRINT);
}
@Override
public void onFingerprintCaptured() {
startFingerprintActivity(MSG_EXTRA_SHOW_SCANNING);
}
@Override
public void finishAuthentication() {
startFingerprintActivity(MSG_EXTRA_CLOSE);
}
private void startFingerprintActivity(final String action) {
final Intent intent = new Intent(context, MobileAuthenticationFingerprintActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(FingerprintActivity.MSG_EXTRA_ACTION, action);
context.startActivity(intent);
}
}
You need to implement the startAuthentication
, onNextAuthenticationAttempt
, onFingerprintCaptured
and finishAuthentication
methods:
startAuthentication(final OneginiMobileAuthenticationRequest oneginiMobileAuthenticationRequest, final OneginiFingerprintCallback oneginiFingerprintCallback)
the app receives new mobile authentication request. First parameter isOneginiMobileAuthenticationRequest
object which contains message you should present to the end user, UserProfile object that specifies request's receiver. Second parameter is a callback object you should use when user accepts or denies incoming request by calling:acceptAuthenticationRequest(pinEnteredByUser)
ordenyAuthenticationRequest
respectively. It also containsfallbackToPin()
method that should be used when user decides not to scan the fingerprint but use PIN.onNextAuthenticationAttempt()
is called when user's fingerprint scan was verified as invalid. Note that scanner will be blocked when used will scan too many his fingerprint too many times without success. This is controlled by Android SDK and the number of attempts might differ depending on device vendor. When the attempts limit will be reached SDK will automatically fallback to PIN authentication.onFingerprintCaptured()
is called when fingerprint was scanned but not yet verified. You can show an information to the user that the verification process just started.finishAuthentication()
is called after end of processing the user response to the request.
Push with FIDO
The fourth type of mobile authentication request is Push with FIDO. In this type the user also have a possibility to accept or deny request. The Push with
FIDO requires the user to authenticate. To support Push with fingerprint type you need to implement OneginiMobileAuthenticationFidoRequestHandler
interface
and set its instance during SDK initialization step by calling
public OneginiClientBuilder setMobileAuthenticationFidoRequestHandler(final OneginiMobileAuthenticationFidoRequestHandler mobileAuthenticationFidoRequestHandler)
method on OneginiClientBuilder
. You also need to handle all interface methods in order to show/hide user interface with a fingerprint input and buttons
allowing to accept or deny request as well as fallback to PIN.
Example how to implement OneginiMobileAuthenticationFidoRequestHandler
public class MobileAuthenticationFidoRequestHandler implements OneginiMobileAuthenticationFidoRequestHandler {
public static OneginiFidoCallback CALLBACK;
private String userProfileId;
private String message;
private final Context context;
public MobileAuthenticationFidoRequestHandler(final Context context) {
this.context = context;
}
@Override
public void startAuthentication(final OneginiMobileAuthenticationRequest oneginiMobileAuthenticationRequest, final OneginiFidoCallback oneginiFidoCallback) {
CALLBACK = oneginiFidoCallback;
userProfileId = oneginiMobileAuthenticationRequest.getUserProfile().getProfileId();
message = oneginiMobileAuthenticationRequest.getMessage();
notifyActivity(COMMAND_START);
}
@Override
public void finishAuthentication() {
notifyActivity(COMMAND_FINISH);
}
private void notifyActivity(final String command) {
final Intent intent = new Intent(context, MobileAuthenticationFidoActivity.class);
intent.putExtra(EXTRA_COMMAND, command);
intent.putExtra(EXTRA_USER_PROFILE_ID, userProfileId);
intent.putExtra(EXTRA_MESSAGE, message);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
You need to implement the startAuthentication
, and finishAuthentication
methods:
startAuthentication(final OneginiMobileAuthenticationRequest oneginiMobileAuthenticationRequest, final OneginiFidoCallback oneginiFidoCallback)
the app receives new mobile authentication request. First parameter isOneginiMobileAuthenticationRequest
object which contains message you should present to the end user, UserProfile object that specifies request's receiver. Second parameter is a callback object you should use when user accepts or denies incoming request by calling:acceptAuthenticationRequest()
ordenyAuthenticationRequest()
respectively. It also containsfallbackToPin()
method that should be used when user decides not to scan the fingerprint but use PIN.finishAuthentication()
is called after end of processing the user response to the request.