User authentication

Introduction

The Onegini SDK uses the oAuth 2.0 protocol to authorize the device to access protected resources. To support this protocol the SDK acts as an oAuth 2.0 client.

Connecting a device

Flow details

  1. APP → SDK: The app initiates authentication on the SDK and provides the required scopes and the handlers to handle the result.
  2. SDK → Token Server: The SDK initializes DCR
  3. Token Server → SDK: The Token Server generates an OCRA challenge.
  4. SDK → Token Server: The SDK creates an OCRA response based on the received challenge.
  5. Token Server → SDK: When the correct OCRA response is received a new set or client credentials is generated and returned.
  6. SDK → Browser: The SDK redirects to the browser to start to perform an authorization request on the token server.
  7. Browser → Token Server: The Token Server authorization endpoint is called.
  8. Token Server → Browser: Redirect to IdP for authentication.
  9. Browser → IdP: Authenticate
  10. IdP → Browser: Redirect to Token Server with authentication result.
  11. Browser → Token Server: Authorize
  12. Token Server → Browser: An authorization grant is being generated after consent was given.
  13. Browser → APP: Redirect back to the app via the configured scheme.
  14. APP → SDK: Delegate the handling of the incoming redirection to the SDK.
  15. SDK → Token Server: Request an access token for the received access grant.
  16. Token Server → SDK: The generated access token with optionally a refresh token is returned to the SDK.

Initializing authentication

To initialize authentication client credentials are required. These credentials are received via Dynamic Client Registration (DCR). As an app developer there is no need to initialize DCR as it is part of the default implementations in the SDK. Errors can occur during DCR, these errors are reported back to the SDK via the specified handler. For DCR the app needs to identify itself to the Token Server. This is done by sending the identifier, version and platform of the app. For the combination of these parameters a signature should be defined on the Token Server. A signature of the app is used which is unique for this particular application and its configuration. To generate an application signature please see the application signature chapter. The signature will be verified via the OCRA protocol. As a timestamp is used within the OCRA protocol it is mandatory that the time on the device is equal to the time on the Token Server, independent of time zones. The maximum time offset is ten minutes. There are two common reasons why DCR would fail. First the time on the device not being in sync and second the app version not properly configured in the Token Server. The SDK does not provide the app with an error other then a general DCR error.

The UserClient exposes two main methods for authentication: UserClient#registerUser() and UserClient#authenticateUser() to support multiple user profiles for the same mobile client. A list (Set<UserProfile>) of registered user profiles can be checked by calling UserClient#getUserProfiles(). When the app is being used for the first time (and the list of profiles is empty), or when user wants to create a new profile, then the registerUser() method should be used. For next authentication the user should be authenticated with authenticateUser() method, that takes specific UserProfile object as a parameter and uses preferred authenticator to log the user in. Optionally, to login with a different authenticator you can use an overload of the UserClient#authenticateUser() method, that takes UserProfile object and OneginiAuthenticator as parameters. The OneginiAuthenticator you want to use must be registered for the given UserProfile. To read more about retrieving the list of registered OneginiAuthenticators please see the Registered/deregistered authenticators section of the OneginiAuthentication chapter.

In both cases, when the user is authenticated, the SDK will call the onSuccess(UserProfile userProfile, CustomAuthenticatorInfo customAuthenticatorInfo) or onSuccess(UserProfile userProfile) methods from respectively the OneginiAuthenticationHandler for UserClient#authenticateUser() or the OneginiRegistrationHandler for UserClient#registerUser() to return the authenticated UserProfile value object. The same value object of the currently authenticated user can be accessed via the UserClient#getAuthenticatedUserProfile() method. Calling UserClient#registerUser() or UserClient#authenticateUser() for an already authenticated user will result in logging the user out and reregistration or reauthentication respectively.

In case of a user authentication failure, the SDK will call the onError(OneginiAuthenticationError error) method with the specific error. This method will also be called when the user denies an authentication request.

The result of authentication is an access token with optionally a refresh token. When a refresh token is available in the authentication flow the SDK will use the refresh token to authenticate. As the refresh token is stored encrypted on the device, the user has to provide his PIN (or a fingerprint) via the specified authentication request handler to decrypt it. In case of the fingerprint authentication, the android system is responsible for recognizing the correct fingerprint - the refresh token will not be accessible when wrong fingerprint will be provided. In case of the PIN authentication, the decrypted refresh token will be send to the Token Server to validate the users pin. When the wrong pin was entered for too many times the SDK will remove the stored refresh token. If the device was used for mobile authentication this won't be possible anymore from this point.

When authenticating for the first time, or when refresh token of particular user profile was revoked, the SDK will instruct the app to redirect the user to the authorization endpoint on the Token Server via the specified browser. When the client credentials are invalid the Token Server is not able to redirect the user back to the app. As this will potentially make the app instance useless unless re-installing the app. The SDK will validate the client credentials and refresh them before redirecting to the token server to receive an access grant.

Example code - registration of a new user profile

OneginiSDK.getOneginiClient(this).getUserClient().registerUser(userProfile, new OneginiRegistrationHandler() {
    @Override
    public void onSuccess(final UserProfile userProfile) {
      // show user is registered and authenticated
    }

    @Override
    public void onError(final OneginiRegistrationError error) {
      // check error reason and handle it or explain it to the user
    }
  }
}

Example code - authentication of already created user profile with preferred authenticator

OneginiSDK.getOneginiClient(this).getUserClient().authenticateUser(userProfile, new OneginiAuthenticationHandler() {
    @Override
    public void onSuccess(final UserProfile userProfile, final CustomAuthenticatorInfo customAuthenticatorInfo) {
      // show user is authenticated
    }

    @Override
    public void onError(final OneginiAuthenticationError error) {
      // check error reason and handle it or explain it to the user
    }
  }
}

Example code - authentication of already created user profile using a specific authenticator

OneginiSDK.getOneginiClient(this).getUserClient().authenticateUser(userProfile, oneginiAuthenticator, new OneginiAuthenticationHandler() {
    @Override
    public void onSuccess(final UserProfile userProfile, final CustomAuthenticatorInfo customAuthenticatorInfo) {
      // show user is authenticated
    }

    @Override
    public void onError(final OneginiAuthenticationError error) {
      // check error reason and handle it or explain it to the user
    }
  }
}

Processing the registration

A result of the registration initialization can be a request for an access grant to the Token Server via the browser. In such case the SDK will notify the app via OneginiRegistrationRequestHandler#startRegistration() method call. The app should use provided url to for ask for the access grant in a separate web browser.

Example opening external browser

  @Override
  public void startRegistration(final Uri uri, final OneginiRegistrationCallback oneginiRegistrationCallback) {
    // we can store the callback in order to pass the registration result later on
    CALLBACK = oneginiRegistrationCallback;

    final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

    context.startActivity(intent);
  }

When user gets his access granted, the Token Server will redirect back to the app. As the app is a layer on top of the SDK, the SDK can not handle this redirect itself. It is the responsibility of the app to handle the redirect and delegate it to the SDK. When delegating a redirect to the SDK the SDK will verify if the redirect has the right syntax and if it should be handled by the SDK. If the SDK decides the redirect should be handled it will continue to process it. The app can handle a redirect by specifying a scheme in the AndroidManifest.xml of the application. Please make sure that you set the same scheme in OneginiConfigModel and in Token Server's configuration

Example AndroidManifest.xml

<application
 ...
  <activity
      android:name=".view.activity.LoginActivity"
      android:launchMode="singleTask">
    <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="oneginiexample"/>
    </intent-filter>
  </activity>
 ...
</application>

Processing a callback includes validation of the callback itself. Errors reported in the callback will be reported to the app via the handler. For a successful callback the SDK will start using the included authorization grant. Based on this authorization grant an access token will be requested for the specified set of scopes. When the client has the refresh token grant type a refresh token will be returned with the created access token for a correct access grant by the Token Server. Once a refresh token is received the SDK will initialize a PIN authentication request to get the users PIN. The PIN is used to store the refresh token encrypted on the device. Depending on the setting chosen by the app developer the user should confirm the entered PIN or not. The PIN authentication request handler can be specified by the app developer by setting it on the OneginiClientBuilder. The received access token will not be persisted and only stored in memory, so it will be gone the next time the app is started.

Example code to handle registration callback

  @Override
  public void onNewIntent(final Intent intent) {
    super.onNewIntent(intent);
    handleRedirection(intent.getData());
  }

  private void handleRedirection(final Uri uri) {
    if (uri == null) {
      return;
    }

    final OneginiClient client = OneginiSDK.getOneginiClient(getApplicationContext());
    final String redirectUri = client.getConfigModel().getRedirectUri();
    if (redirectUri.startsWith(uri.getScheme())) {
      // here we can call the OneginiRegistrationCallback stored in previous step
      if (CALLBACK != null) {
        CALLBACK.handleRegistrationCallback(uri);
        CALLBACK = null;
      }
    }
  }

When calling the OneginiRegistrationCallback#handleRegistrationCallback method there is no need to specify a handler, because the OneginiRegistrationHandler handler from the registration callis used instead. In case when the registration in web browser has failed or was aborted by the user, you can call OneginiRegistrationCallback#denyRegistration() method in order to abort registration process.

Logout a user

In the SDK a user is treated as logged in as long as the user has an access token for the operation to be executed. To logout the user the access token should be removed. This can be done by calling the logout function on the UserClient. The SDK will also send a request to the Token Server to remove the access token to ensure the token is invalidated both on the client as server side. If a refresh token is available this will still be available after the logout action.

Example code to logout a user

OneginiClient.getInstance().getUserClient().logout(

  new OneginiLogoutHandler() {
   @Override
   public void onSuccess() {
     // Go to home screen
   }

   @Override
   public void onError(final LogoutError error) {
     // Handle the error or simply ignore and return to home screen
   }
 }
);

Deregister user profile

Deregistering a user profile implies the removal of all his data (including access and refresh tokens) from the device. The SDK will also send a request to the Token Server to revoke all profile's tokens. The client credentials and other user profiles will remain stored on the device.

Example code to deregister a user profile

OneginiClient.getInstance().getUserClient().deregisterUser(userProfile, new OneginiDeregisterUserProfileHandler() {
    @Override
    public void onSuccess() {
        // Go to home screen
    }

    @Override
    public void onError(OneginiDeregistrationError error) {
        // Handle the error or simply ignore and return to home screen
    }
 }
);

Schematics authentication with PIN

Authentication with PIN

Forgot pin

The refresh token is stored encrypted on the device. For encryption of the token a PIN is used as an encryption key. When a user forgot his PIN the existing refresh token used to log in can't be decrypted and is useless in that sense. After few wrong PIN attempts (configurable on Token Server) the refresh token is removed automatically in both the SDK as on the server side. To provide the user an option to skip this three attempts before the refresh token is gone the deregister user profile functionality can be used. Once the refresh token is removed the user needs to re-authenticate and has to choose a new pin.