Authenticate user with custom authenticator

Introduction

The SDK allows you to authenticate users with 3rd party (custom) authenticators. In such case you (or the custom authenticator library) are responsible for authenticating the user when requested and return the authentication result (success, failure or exception) back to the Onegini SDK. In order to use the custom authentication feature, you need to first enable and configure the feature on the Token Server side. Please read the Token Server docs for more info.

OneginiCustomAuthenticator

In order to use a custom authenticator, you should provide an implementation of the OneginiCustomAuthenticator interface to the SDK. The implementation provides the unique ID of an authenticator along with methods that should be called to register, deregister or authenticate using the custom authenticator. These methods are named by the SDK as Actions and are defined by interfaces: OneginiCustomAuthRegistrationAction, OneginiCustomAuthDeregistrationAction, and OneginiCustomAuthAuthenticationAction.

Example code for custom authenticator implementation

public class BasicCustomAuthenticator implements OneginiCustomAuthenticator {

  private final OneginiCustomAuthRegistrationAction registrationAction;
  private final OneginiCustomAuthDeregistrationAction deregistrationAction;
  private final OneginiCustomAuthAuthenticationAction authAuthenticationAction;

  public BasicCustomAuthenticator(final Context context) {
    registrationAction = new BasicCustomAuthRegistrationAction(context);
    deregistrationAction = new BasicCustomAuthDeregistrationAction(context);
    authAuthenticationAction = new BasicCustomAuthAuthenticationAction(context);
  }

  @Override
  public OneginiCustomAuthRegistrationAction getRegistrationAction() {
    return registrationAction;
  }

  @Override
  public OneginiCustomAuthDeregistrationAction getDeregistrationAction() {
    return deregistrationAction;
  }

  @Override
  public OneginiCustomAuthAuthenticationAction getAuthenticationAction() {
    return authAuthenticationAction;
  }

  @Override
  public String getId() {
    return "EXPERIMENTAL_CUSTOM_AUTHENTICATOR_ID";
  }
}

OneginiCustomAuthRegistrationAction

The OneginiCustomAuthRegistrationAction interface defines a method that should be called when the SDK requires the custom authenticator registration. When the OneginiCustomAuthRegistrationAction#finishRegistration method is called, you should start the registration process and return the final result on the provided OneginiCustomAuthRegistrationCallback. It consists of three methods:

  • void acceptRegistrationRequest(String optionalRegistrationData) that should be called when the custom authenticator registration has succeeded,
  • void denyRegistrationRequest() which should be triggered when the custom authenticator registration has been canceled,
  • void returnError(Exception e) that should be invoked when the custom authenticator registration has returned an error.

Example code for custom authenticator registration action implementation

public class BasicCustomAuthRegistrationAction implements OneginiCustomAuthRegistrationAction {

  public static OneginiCustomAuthRegistrationCallback CALLBACK;

  private final Context context;

  public BasicCustomAuthRegistrationAction(final Context context) {
    this.context = context;
  }

  @Override
  public void finishRegistration(final OneginiCustomAuthRegistrationCallback callback) {
    CALLBACK = callback;

    final Intent intent = new Intent(context, BasicAuthenticatorRegistrationActivity.class);
    context.startActivity(intent);
  }
}

OneginiCustomAuthDeregistrationAction

The OneginiCustomAuthDeregistrationAction interface defines a method that should be called when the SDK requires the custom authenticator deregistration. When the OneginiCustomAuthDeregistrationAction#finishDeregistration method is called, you should start the deregistration process and return the final result on the provided OneginiCustomAuthDeregistrationCallback. It consists of three methods:

  • void acceptDeregistrationRequest(String optionalDeregistrationData) that should be called when the custom authenticator deregistration has succeeded,
  • void denyDeregistrationRequest() which should be triggered when the custom authenticator deregistration has been canceled,
  • void returnError(Exception e) that should be invoked when the custom authenticator deregistration has returned an error.

Example code for custom authenticator deregistration action implementation

public class BasicCustomAuthDeregistrationAction implements OneginiCustomAuthDeregistrationAction {

  public static OneginiCustomAuthDeregistrationCallback CALLBACK;

  private final Context context;

  public BasicCustomAuthDeregistrationAction(final Context context) {
    this.context = context;
  }

  @Override
  public void finishDeregistration(final OneginiCustomAuthDeregistrationCallback callback, final String s) {
    CALLBACK = callback;

    final Intent intent = new Intent(context, BasicAuthenticatorDeregistrationActivity.class);
    context.startActivity(intent);
  }
}

OneginiCustomAuthAuthenticationAction

The OneginiCustomAuthAuthenticationAction interface defines a method that should be called when the SDK requires the custom authenticator authentication. When the OneginiCustomAuthAuthenticationAction#finishAuthentication method is called, you should start the authentication process and return the final result on the provided OneginiCustomAuthAuthenticationCallback. It consists of two methods:

  • void returnSuccess(String optionalAuthenticationData) that should be called when the custom authenticator authentication has succeeded,
  • void returnError(Exception e) that should be invoked when the custom authenticator authentication has failed.

Example code for custom authenticator authentication action implementation

public class BasicCustomAuthAuthenticationAction implements OneginiCustomAuthAuthenticationAction {

  public static OneginiCustomAuthAuthenticationCallback CALLBACK;

  private final Context context;

  public BasicCustomAuthAuthenticationAction(final Context context) {
    this.context = context;
  }

  @Override
  public void finishAuthentication(final OneginiCustomAuthAuthenticationCallback callback, final String s) {
    CALLBACK = callback;

    final Intent intent = new Intent(context, BasicAuthenticatorAuthenticationActivity.class);
    context.startActivity(intent);
  }
}

Authentication handlers

The SDK provides two interfaces (OneginiCustomAuthenticationRequestHandler and OneginiMobileAuthWithPushCustomRequestHandler for respectively: regular and push authentication) that you can implement in your application to use your custom authentication. Later you will need to provide them to OneginiClientBuilder instance, together with the OneginiCustomAuthenticator implementation, as shown below:

Example code for supplying custom authenticator to the SDK

    new OneginiClientBuilder(applicationContext, registrationRequestHandler, createPinRequestHandler, pinAuthenticationRequestHandler)
        .setCustomAuthenticationRequestHandler(new BasicCustomAuthenticationRequestHandler(context))
        .setMobileAuthWithPushCustomRequestHandler(new MobileAuthenticationBasicCustomRequestHandler(applicationContext))
        .addCustomAuthenticator(new BasicCustomAuthenticator(applicationContext))
        .build();

OneginiCustomAuthenticationRequestHandler interface exposes two methods you should use to control the process of authenticating the user:

  • void startAuthentication(UserProfile userProfile, OneginiCustomCallback callback) triggered when new custom authentication request is made, providing the UserProfile object and the result callback;
  • void finishAuthentication() triggered when custom authentication finished either with a success or an error.

OneginiMobileAuthWithPushCustomRequestHandler works in exactly the same manner with a single change in parameters of startAuthentication() method, where instead of the UserProfile you get the OneginiMobileAuthenticationRequest object containing information about the push request as well as the UserProfile.

Example code for OneginiCustomAuthenticationRequestHandler implementation

public class BasicCustomAuthenticationRequestHandler implements OneginiCustomAuthenticationRequestHandler {

  public static OneginiCustomCallback CALLBACK;

  private final Context context;
  private String userProfileId;

  public BasicCustomAuthenticationRequestHandler(final Context context) {
    this.context = context;
  }

  @Override
  public void startAuthentication(final UserProfile userProfile, final OneginiCustomCallback oneginiCustomCallback) {
    CALLBACK = oneginiCustomCallback;
    userProfileId = userProfile.getProfileId();
    notifyActivity(COMMAND_START);
  }

  @Override
  public void finishAuthentication() {
    notifyActivity(COMMAND_FINISH);
  }

  private void notifyActivity(final String command) {
    final Intent intent = new Intent(context, CustomAuthActivity.class);
    intent.putExtra(EXTRA_COMMAND, command);
    intent.putExtra(EXTRA_USER_PROFILE_ID, userProfileId);
    intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(intent);
  }
}

To control the flow of custom authentication you should use provided OneginiCustomCallback callback. It consists of three methods:

  • acceptAuthenticationRequest() that should be called when user accepts the custom authentication request,
  • denyAuthenticationRequest() which should be triggered when user denies the custom authentication request,
  • fallbackToPin() that should be invoked when user decides to resign from the custom authentication and wants to enter his PIN to finish the authentication.

Custom authenticator registration and authentication

In order to register the custom authenticator or authenticate with it you should use the same methods like for other OneginiAuthenticators: UserClient#registerAuthenticator(final OneginiAuthenticator authenticator, final OneginiAuthenticatorRegistrationHandler handler), UserClient#authenticateUser(final UserProfile userProfile, final OneginiAuthenticationHandler authenticationHandler), or UserClient#authenticateUser(final UserProfile userProfile, final OneginiAuthenticator oneginiAuthenticator, final OneginiAuthenticationHandler authenticationHandler).

Example custom authenticator registration

//to register the custom authenticator
OneginiSDK.getOneginiClient(context).getUserClient().registerAuthenticator(customAuthenticator, new OneginiAuthenticatorRegistrationHandler() {
    @Override
    public void onSuccess(final CustomAuthenticatorInfo customAuthenticatorInfo) {
      // successfully registered authenticator
    }

    @Override
    public void onError(final OneginiAuthenticatorRegistrationError oneginiAuthenticatorRegistrationError) {
      // handle different errors
    }
});

The only difference between the custom authenticator and other authenticator types (PIN, Fingerprint) is that in case of a custom authenticator you can receive a non-null info object CustomAuthenticatorInfo in both successful and failed registration/authentication attempt. In case of a success the object is passed as a param in onSuccess() method of the registration/authentication attempt. In case of an error, the info object can be received by calling getErrorDetails().getCustomAuthenticatorInfo() methods on the error object.

new OneginiAuthenticationHandler() {
  @Override
  public void onSuccess(final UserProfile userProfile, final CustomAuthenticatorInfo customAuthenticatorInfo) {
    // customAuthenticatorInfo passed as a param
  }

  @Override
  public void onError(final OneginiAuthenticationError oneginiAuthenticationError) {
    // customAuthenticatorInfo passed through error object
    oneginiAuthenticationError.getErrorDetails().getCustomAuthenticatorInfo();
  }
};

The CustomAuthenticatorInfo contains the status code and the data that were returned by the registration / authentication script implemented in the Extension Engine. In case of other authenticator types, or when custom authenticator has failed before the server request call, the object will be null.

This solution allows you to debug the custom authentication process and/or perform further actions when the app receives specific authentication code or data. The Onegini SDK also uses the status code returned in CustomAuthenticatorInfo to determine, if the registration/authentication was successful (when the code is 2000) or has failed (when code is 4000 or 5000).