Skip to main content
Skip table of contents

TB.Identity SDK (Android)

The SDK is available on demand. Please contact your TrustBuilder's point of contact.

The TB.Identity SDK allows you to develop a mobile app that runs natively on a device. Native mobile applications can use native or browser-based login flows.

In a hosted login flow, the user is shown a web browser and redirected to the TrustBuilder hosted login page for sign up or log in. For example: an iOS application opens a SafariViewController or an Android application opens a Custom Chrome Tab.

With a native login flow, the user signs up or enters their password directly into the app. Note, however, that when using external IDPs, an iOS app may still open a SafariViewController and an Android app may still open a Custom Chrome Tab for the interaction with external IDPs.

Regardless of which option you choose, TrustBuilder supports either.

TB.Identity SDK is a mobile SDK for communicating using OAuth 2.0 and OpenID Connect. It maps the raw protocol flows and adds convenience methods to assist with common tasks like performing an action with fresh tokens and to obtain user profile information.

2a3a7689-4a3d-48dd-8aa5-701c9e227f9d (1).png

Best practice

The TB.Identity SDK wraps following functionality:

  • Secure protocol handling

  • Secure token lifecycle

  • Secure user profile access

  • Persona-driven policies

  • Handle session obligations

  • Handle onboarding obligations

  • Blacklist checking

Phishing/security concerns: an unauthorized party could decompile or intercept traffic to/from your application to get the Client ID and authentication URL. With this information the unauthorized party could create a rogue application, upload it to an application store, and use it to phish for usernames, passwords, and Access Tokens.

An authorization request is dispatched to the TrustBuilder.IO AuthorizationService instance, and the response will be dispatched to the activity of your choice, expressed via an Intent. The TB.Identity SDK supports the PKCE extension to OAuth which was created to secure authorization codes in public clients when custom URI scheme redirects are used. The TB.Identity SDK encapsulates the authorization state of the user and communicates with the TrustBuilder.IO platform.

Token requests, such as obtaining a new access token using a refresh token, follow a similar pattern and are dispatched to TrustBuilder.IO, and a token response instance is returned via a callback. Responses update the authorization state in order to track and persist changes. Once in an authorized state, access tokens can be automatically refreshed as necessary before performing actions that require valid tokens.

The TB.Identity SDK follows best practice set out in RFC 8252 - OAuth 2.0 for Native Apps, authorization requests from native apps should only be made through external user-agents, primarily the user's browser. For this reason, WebView is explicitly not supported for security reasons.RFC 8252 OAuth 2.0 for Native Apps. Using a web browser for OAuth and OIDC is not only a security imperative but also a user experience advantage. By leveraging trusted browser environments and educating users on the benefits, we can ensure a seamless and secure authentication process.

  • RFC 8252 Guidelines as defined by IETF

    • https://datatracker.ietf.org/doc/html/rfc8252

    •  OAuth 2.0 and Native Apps: OAuth 2.0 authorization requests from native apps should only be made through external user-agents, primarily the user's browser. This is a security best practice as outlined in RFC 8252.

    • Prohibition of Embedded User-Agents: Native apps must not use embedded user-agents for authorization requests. Embedded user-agents can compromise security by allowing access to the user's full authentication credentials.

  • Google's Stance on WebView

  • System Browser as a Secure Alternative

  • Platform standard implementation

    • iOS and Android: Both platforms provide specific ways to initiate authorization in a browser (e.g., iOS's SFSafariViewController/SFAuthenticationSession and Android's Custom Tab feature), ensuring a seamless and secure experience.

    • Google's OAuth Policies: Google's OAuth policies emphasize the use of browsers over embedded webviews, aligning with security best practices. (https://developers.google.com/identity/protocols/oauth2/policies#browsers )

  • User Experience Considerations

    • Trust and Familiarity: Users generally trust their browser environment. Features like address verification in browsers enhance trust compared to embedded webviews.

    • Platform Standards and Security: The embedded browser is a platform standard for both iOS and Android. Prioritizing security, users can benefit from the familiar interface of their system browser.

    • Educating Users: Instead of compromising security, educating users through an onboarding flow can enhance their understanding and acceptance of browser-based authentication.

    • Cancellation handling: Because having alternative flows when the user intentionally closes could be desired, we allow checking on that specific flow.

1. Configure TrustBuilder

To use TrustBuilder services, you need to have an application set up in the TrustBuilder Dashboard. The TrustBuilder application is where you will configure authentication in your project.

1.2 Configure your application

Use the Admin Portal to configure a new TrustBuilder application or select an existing application that represents the project you want to integrate with. Every application in TrustBuilder is assigned an alphanumeric, unique client ID that your application code will use to call TrustBuilder APIs through the SDK.

1.3 Configure callback URLs

A callback URL is the application URL that TrustBuilder will direct your users to once they have authenticated. If you do not set this value, TrustBuilder will not return users to your application after they log in.

1.4 Configure logout URLs

A logout URL is the application URL TrustBuilder will redirect your users to once they log out. If you do not set this value, users will not be able to log out from your application and will receive an error.

2. Install the TB.Identity SDK

2.1 Move all files to library folder

Move the following files into the library folder of your Android project. In this guide we use 'libs' folder.

  • TB.Identity.aar

  • VDDocumentCapture.aar

  • VDPhotoSelfieCapture.aar

  • VDLibraryCommonCore.aar

  • VDLibraryCommonCoreJvm.jar

  • VDLibraryCommonImageProcessing.aar

  • VDLogger.aar

2.2 Gradle dependencies

Add the library files to your dependencies in your Android build.gradle file. This can be done in 2 ways.
Also add extra dependencies, required by us or the Veridas SDK.

CODE
dependencies {
    //  <Your Android project dependencies>
    ...
    // TB.Identity packages
    // 1. Add each file individually:
    implementation files('libs/TB.Identity.aar')
    implementation files('libs/VDDocumentCapture.aar')
    implementation files('libs/VDPhotoSelfieCapture.aar')
    implementation files('libs/VDLibraryCommonCore.aar')
    implementation files('libs/VDLibraryCommonCoreJvm.jar')
    implementation files('libs/VDLibraryCommonImageProcessing.aar')
    implementation files('libs/VDLogger.aar')
    
    // 2. OR add all .aar and .jar files in your libs folder:
    implementation fileTree(dir: 'libs', include: ['*.aar'])
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    
    // Extra dependencies required for the TB.Identity SDK
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.11.0'
    implementation 'net.openid:appauth:0.11.1'
    implementation 'androidx.security:security-crypto:1.1.0-alpha06'
    implementation 'com.google.code.gson:gson:2.10.1'
    implementation 'com.squareup.okhttp3:okhttp:4.11.0'
    implementation 'com.auth0.android:jwtdecode:2.0.2'
    implementation 'androidx.exifinterface:exifinterface:1.3.7'
    implementation 'androidx.legacy:legacy-support-v13:1.0.0'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    implementation 'com.github.bumptech.glide:glide:4.16.0'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22"
    implementation group: 'net.lingala.zip4j', name: 'zip4j', version: '2.9.1'
}

You can change the versions of the dependencies, although we can't guarantee that the SDK will still work if you do.

2.3 AndroidManifest

The following settings are required in your AndroidManifest on your "Application" level.

CODE
<application
    android:largeHeap="true"
    android:allowBackup="false"
    tools:replace="android:allowBackup"
    ...
</application>

To handle the redirect after authorization you need to setup the "appAuthRedirectScheme". You can do this by adding the following in your AndroidManifest.xml file in <application>:

CODE
<activity
    android:name="net.openid.appauth.RedirectUriReceiverActivity"
    tools:node="replace"
    android:exported="true">
    <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="${appAuthRedirectScheme}"/>
    </intent-filter>
</activity>

In your build.gradle add the domain for redirects. This should be aligned with the redirectUri used when creating an instance of TBService and your IDHUB settings.

When your redirect Uri is: "com.yourcompany.yourapplication://login-callback" your appAuthRedirectScheme would be "com.yourcompany.yourapplication"

CODE
manifestPlaceholders = [
    'appAuthRedirectScheme': '<App domain used for redirect>'
]

2.4 Creating the TBLoginService

First, ensure that you have created an instance of the TBLoginService for either the browser flow or the native flow.

  • For the Browser flow:

    CODE
    TBLoginService tbService = TBLoginService.createBrowserService(
        Uri authorizationEndpoint: <your authorization endpoint>,
        Uri tokenEndpoint: <your token endpoint>,
        Uri endSessionEndpoint: <your end session endpoint>,
        String clientId: <your client id>,                                                        
        Uri redirectUri: <your configured redirect url>,
        double expirationThreshold: <Threshold to be used for fetching new tokens>, 
        Context context: <Your Android Application context>)
  • For the native flow:

    CODE
    TBLoginService tbService = TBLoginService.createNativeService(
        Uri idpStepUpEndpoint: <your allowed step-ups endpoint>,
        Uri authorizationEndpoint: <your authorization endpoint>,
        Uri tokenEndpoint: <your token endpoint>,
        Uri endSessionEndpoint: <your end session endpoint>,
        String clientId: <your client id>,                                                        
        Uri redirectUri: <your configured redirect url>,
        double expirationThreshold: <Threshold to be used for fetching new tokens>,  
        Context context: <Your Android Application context>)

This instance will allow you to access all of the behavior that is facilitated in this SDK.
Behind the scenes, we will also retrieve a fresh access token automatically when trying to retrieve information from the UserInfo API.

  • authorizationEndpoint
    The endpoint used for the authorization. This is configured in TrustBuilder portal.
    An example of a authorization endpoint can be yourcompany.trustbuilder.io/idhub/oidc/v1/authorize

  • tokenEndpoint
    The endpoint used to fetch the tokens. This is configured in TrustBuilder portal.
    An example of a token endpoint can be yourcompany.trustbuilder.io/idhub/oidc/v1/token

  • endSessionEndpoint
    The endpoint used to logout the user. This is configured in the TrustBuilder portal.
    An example of a end session endpoint can be yourcompany.trustbuilder.io/idhub/oidc/v1/logout

  • clientId
    OAuth 2.0 Client Identifier valid at the Authorization Server.

  • redirectUri
    Redirection URI to which the response will be sent. This URI MUST exactly match one of the Redirection URI values for the Client pre-registered at the TrustBuilder portal under the correct Service Provider(simple string comparison)

  • tokenRefreshThreshold
    The tokenRefreshThreshold will be used during the check whether a token is still valid or not. This way it's possible to already refresh a token a bit before it's actually expired.
    This value should be identical with the value configured in TrustBuilder.

  • context
    The Android Application context. This is required for the SDK to use secure storage for the authorization tokens.

2.5 Creating the TBOnboardingService

First, ensure that you have created an instance of the TBOnboardingService.

CODE
TBOnboardingService tbOnboardingService = TBOnboardingService.createOnboardingService(
    Uri tenantUrl: <your tenantUrl>,
    Context context: <Your Android Application context>,
    List<String> documentIds: <IDs of the documents you allow>,
    Map<String, String> documentConfiguration: <The UI configuration of the document scanner>,
    Map<String, String> selfieConfiguration: <The UI configuration of the selfie scanner>)

3. TBLoginService - Hosted Login

The authentication flow via the browser can be triggered using the authenticateWithBrowser method on your instance of TBLoginService.

3.1 Sign in

Android will use the on ActivityResult of your Activity to handle the browser result. This result needs to be passed to the SDK.
Then the SDK will fetch the tokens and store these in a secure storage.

You need to include:

  • Your Android Activity

  • Your scopes. These are configured in IDHUB and should match.

  • The instance that implements ITBServiceCallback

Once that is finished authenticateWithBrowserITBServiceCallback.onTBServiceResult will be triggered.

This interface (ITBServiceCallback) needs to be implemented in your code.

The following steps are required:

  1. Start the authorize flow

  2. Catch the ActivityResult and pass the result to the SDK (onAuthenticationResult)

  3. ITBServiceCallback will be triggered with success or an error.

Usage

CODE

// Your Android Activity that also implements ITBServiceCallback.
 
// Execute the following to start the authorize flow
public void authorize(Activity activity){
    List<String> scopes = Arrays.asList("openid", "users:self");
 
    tbService.authenticateWithBrowser(activity, scopes, this);
}
 
// Your Android Activity will capture the result. Pass this to the SDK.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
 
    tbLoginService.onAuthenticationResult(requestCode, data, this);
}
 
// Result of be send via this callback. 
// EResultContext indicates if it's concerning Login or Logout flow.
@Override
public void onTBServiceResult(@NonNull Result<EResultContext> result) {
    ...
}

3.2 Accessing the token

When later in your application you want to access the token to authorize your api calls with, you can simply use getAndRefreshTokenWhenNecessary on that same TBLoginService instance.
You are technically not required to use that same instance, but you can create a new one with the same configuration.

This method will check whether the token is at least valid for the time in the given threshold when the instance TBLoginService was created.
When that is not the case, the SDK will try to refresh the access token and return the refreshed one.

Usage

CODE
public void getToken(Activity activity){
    Future<Result<String>> future = tbLoginService.getTokenAndRefreshWhenNeeded(activity);
    Result<String> result = future.get();
}

3.3 User canceled flow

When the user canceled the flow the SDK will return an AuthorizationException with the following properties:

  • Code: 1

  • errorDescription: "User canceled flow"

  • detailMessage: "User canceled flow"

4. TBLoginService - Native Login

The native flow will work differently than the Browser flow. First, the different Identity Providers can be retrieved from the TB.Identity SDK. The native flow will start by fetching the allowed IDPs. You can do this by executing getAllowedIDPs.

4.1 GetAllowedIDPs

The getAllowedIDPs method will return a list of TBIdentityProvider. These Identity Providers can be used to authenticate.
This list can be represented visually any way in your application you want.
However, it is important to keep the instance of TBIdentityProvider as we will need it later on to sign the user in.

Usage

CODE
// Execute the following to fetch the allowed IDPs
public void getAllowedIDPs(Activity activity){
    Future<Result<List<TBStepUp>>> future = tbLoginService.getAllowedIDPs();
    Result<List<TBStepUp>> result = future.get();
 
    // Show the list of IDPs
    ...
}

4.2 Sign in

Once the user of your application has chosen the Identity Provider, that instance can be used to start the sign-in flow.
For this: the authenticateWithIDP method on the instance of TBService can be used.

You need to include:

  • Your Android Activity

  • The chosen Identity Provider

  • Your scopes. These are configured in IDHUB and should match.

  • The instance that implements ITBServiceCallback

Android will use the on ActivityResult of your Activity to handle the browser result. This result needs to be passed to the SDK.
Then the SDK will fetch the tokens and store these in secure storage.

Once that is finished, authenticateWithBrowserITBServiceCallback.onTBServiceResult will be triggered.

This interface (ITBServiceCallback) needs to be implemented in your code.

The following steps are required:

  1. Start the authorize flow with the chosen TBIdentityProvider

  2. Catch the ActivityResult and pass the result to the SDK using onAuthenticationResult 

  3. ITBServiceCallback  will be triggered with success or an error.

Usage

CODE

// Your Android Activity that also implements ITBServiceCallback.
 
// Execute the following to start the native authorize flow
public void authorize(Activity activity, TBIdentityProvider idp){
    List<String> scopes = Arrays.asList("openid", "users:self");
 
    tbLoginService.authenticateWithIDP(activity, idp, scopes, this);
}
 
// Your Android Activity will capture the result. Pass this to the SDK.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
 
    tbLoginService.onAuthenticationResult(requestCode, data, this);
}
 
// Result of be send via this callback. 
// EResultContext indicates if it's concerning Login or Logout flow.
@Override
public void onTBServiceResult(@NonNull Result<EResultContext> result) {
    ...
}

4.3 Accessing the token

When later in your application you want to access the token to authorize your api calls with, you can simply use getAndRefreshTokenWhenNecessary on that same TBLoginService instance.
You are technically not required to use that same instance, but you can create a new one with the same configuration.

This method will check whether the token is at least valid for the time in the given threshold when the instance TBLoginService was created.
When that is not the case, the SDK will try to refresh the access token and return the refreshed one.

Usage

CODE
public void getToken(Activity activity){
    Future<Result<String>> future = tbLoginService.getTokenAndRefreshWhenNeeded(activity);
    Result<String> result = future.get();
}

4.4 User canceled flow

When the user canceled the flow the SDK will return an AuthorizationException with the following properties:

  • Code: 1

  • errorDescription: "User canceled flow"

  • detailMessage: "User canceled flow"

5. TBLoginService - UserInfo

The information that can be retrieved from can also be accessed from the same TBLoginService instance.

5.1 Get user details

In order to retrieve the details for the currently signed in User, the method getCurrentUser can be used on the same instance of TBLoginService.
This method will retrieve the information about the current authorized user and return it in the form of TBUser.

Usage

CODE
public void getCurrentUser(Activity activity){
    Future<Result<TBUser>> future = tbLoginService.getCurrentUser(activity);
    Result<TBUser> user = future.get();
}

5.2 Patch User Details

In order to update some properties of the user, the retrieved TBUser instance can simply be updated and sent to the SDK with the patchUser method on the same TBLoginService instance.

Usage

CODE
public void patchUser(Activity activity){
    user.familyName = "updated family name"                 
 
    Future<Result<TBUser>> future = tbLoginService.patchUser(user, activity);
    Result<TBUser> result = future.get();
}

6. TBLoginService - Personas

6.1 Get list of personas

In order to retrieve the list of personas for the current signed in user. You can use the getListOfPersonas method on the instance of TBLoginService.

Behind the scenes, we will automatically use the information of the currently signed in user to retrieve the personas that the user can select.

Usage

CODE
public void getListOfPersonas(Activity activity){
    Future<Result<List<TBPersona>>> future = tbLoginService.getListOfPersonas(activity);
    Result<List<TBPersona>> result = future.get();
}

6.2 Select persona

In order to retrieve a single persona based on a given personaId you can use the selectPersona method on the same instance of TBLoginService. Based on the currently authorized user and the given persona, the detail information of that persona will be retrieved.

Usage

CODE
public void selectPersona(TBPersona persona, Activity activity){
    Future<Result<TBPersonaInformation>> future = tbLoginService.selectPersona(persona, activity);
    Result<TBPersonaInformation> result = future.get();
}

6.3 Patch persona attributes

In order to update the attributes of a specific persona, you can use updatePersonaAttributes.
This method expects the originally retrieved instance of TBPersonaInformation from selectPersona with the updated attributes. We need this original instance to correctly update the information. Hence there is also no public constructor available of TBPersonaInformation.

Usage

CODE
public void updatePersonaAttributes(TBPersonaInformation persona, Activity activity) {
 
    for (TBAttribute attribute : persona.attributes.editableAttributes) {
        // You can edit the values of an existing attribute
        attribute.values = Collections.singletonList("TRUE");
    }
    
    // Here we delete every attribute besides the first attribute.     
    persona.attributes.editableAttributes = Collections.singletonList(persona.attributes.editableAttributes.get(0));
 
    Future<Result<TBPersonaInformation>> future = tbLoginService.updatePersonaAttributes(persona, activity);
    Result<TBPersonaInformation> value = future.get();
}

7. TBOnBoardingService

7.1 Start Document Onboarding

This method will execute the following flow:

  1. Start a validation session

  2. Start the document scanner to scan documents and upload said documents

  3. Start the selfie scanner and upload said selfie

  4. Request and return the validation result.

The result will contain a

  • Validation ID

  • Indication whether the verification was successful.

Requirements:

In order to start the onboarding flow you need a bearer token of an authenticated user with the correct claims. You can use your instance of TBOnboardingService to start this flow.

Usage

CODE
public void StartOnboarding(){
    Future<Result<TBValidationResult>> future = tbOnboardingService.StartOnboarding("BEARER TOKEN");
    Result<TBValidationResult> validationResult = future.get();
}

7.2 Session expired

Behind the scenes we will start a validation session that will only be valid for a certain amount of time. If the end-user takes to long to complete the flow, there might be an unsuccessful response with a SessionExpiredException.

8. Response Handling

Most methods returns a Result object.

This Result object has the following properties:

  • Value: The returned value. This can be 'null' if something went wrong.

  • Exception: An exception in case something went wrong. eg. not signed in, api error,...

  • isSuccess: Boolean to indicate if the executed method was successful.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.