Skip to main content
Skip table of contents

TB.Identity SDK

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.

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 Creating the TBService

First, ensure that you have created an instance of the TBService  for either the browser flow or the native flow.
For the Browser flow:

GO
TBService tbService = TBService.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

JS
TBService tbService = TBService.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 behaviour 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 the IDHUB 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 the IDHUB 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 IDHUB portal.
An example of a end session endpoint can be {yourcompany}.trustbuilder.io/idhub/oidc/v1/logout

clientId

OAuth 2.0 Client Identifier as configured by TrustBuilder - see section 1.2.

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) - see section 1.3.

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 IDHUB.

context

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

2.2 AndroidManifest

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>:

XML
 <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"

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

2.3 Gradle dependencies

Add the following dependencies in your Android build.gradle file:

JS
dependencies {
    //  <Your Android project dependencies>
    ...
    // TB.Identity packages
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation files('libs/TB.Identity.aar')
    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.TrustBuilder.android:jwtdecode:2.0.2'
}

3. Hosted Login

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

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

JS
// 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);
    tbService.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 TBService 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 TBService was created.
When that is not the case, the SDK will try to refresh the access token and return the refreshed one.

Usage

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

3.3 User cancelled flow

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

  • Code: 1

  • errorDescription: "User cancelled flow"

  • detailMessage: "User cancelled flow"

4. 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

JS
// Execute the following to fetch the allowed IDPs
public void getAllowedIDPs(Activity activity){
    Future<Result<List<TBStepUp>>> future = tbService.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 IdentityProvider, 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

JS
// 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");
    tbService.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);
    tbService.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 TBService 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 TBService was created.
When that is not the case, the SDK will try to refresh the access token and return the refreshed one.

Usage

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

4.4 User cancelled flow

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

  • Code: 1

  • errorDescription: "User cancelled flow"

  • detailMessage: "User cancelled flow"

5. UserInfo

The information that can be retrieved from can also be accessed from the same TBService instance.4.1    User Details

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 TBService.
This method will retrieve the information about the current authorized user and return it in the form of TBUser.

Usage

JS
public void getCurrentUser(Activity activity){
    Future<Result<TBUser>> future = tbService.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 TBService instance.

Usage

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

6. 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 TBService.

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

JS
public void getListOfPersonas(Activity activity){
    Future<Result<List<TBPersona>>> future = tbService.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 TBService. Based on the currently authorized user and the given persona, the detail information of that persona will be retrieved.

Usage

GO
public void selectPersona(TBPersona persona, Activity activity){
    Future<Result<TBPersonaInformation>> future = tbService.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

JS
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 = tbService.updatePersonaAttributes(persona, activity);
    Result<TBPersonaInformation> value = future.get();
}

7. 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: Bolean 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.