Skip to content

Trimble Identity OAuth Android Library - Developer Guide (Preview)

Content

  1. Overview

  2. Authentication with Trimble Identity

  3. Requirements

  4. Installation

  5. Code snippets

  6. FAQ

Overview

This preview version of the library introduces Offline Support and Multi-User Account Management capabilities while maintaining all the core features from the stable version. The library uses PKCE extension to OAuth which was created to secure authorization codes in public clients when custom URI scheme redirects are used. It features Token persistence, Trusted Web Activity(TWA) support, Managed users support, Multi-User Account Management for handling multiple user accounts within a single application, and Offline Authentication for secure login without internet connectivity using passkeys.

Preview Features:

  • Offline Authentication: Login without internet connection using passkeys (requires initial online login)
  • MultiUserAccountManager: Manage up to 5 user accounts simultaneously
  • Account Switching: Seamlessly switch between different user accounts in both online & offline mode.
  • Automatic Account Management: Least Recently Used (LRU) account removal when limit is reached
  • Enhanced Login Options: Force new login to bypass SSO for multi-user scenarios

CustomTabs are used for authorizing requests when Custom Tabs implementation is provided by a browser on the device (for example by Chrome). Otherwise, the default browser is used as a fallback.

Authentication with Trimble Identity

To utilize TID authentication, your identity application must be registered with Trimble Identity. You can conveniently handle the application registration process on Trimble Developer Console.

Requirements

Provides compatibility from Android API 23 and above with minimum JDK of 1.8

Custom URI Scheme

  • Once the authorization flow is completed in the browser, the authorization service will redirect to a URI specified as part of the authorization request, providing the response via query parameters. In order for your app to capture this response, a Custom scheme based redirect URI is used. URI needs to include applicationId of the end application ( applicationId /path ). Redirect uri for login and logout needs to be constructed using the custom uri scheme.
  • End application should specify the appAuthRedirectScheme in their module level build.gradle inside defaultConfig block
manifestPlaceholders = ['appAuthRedirectScheme': applicationId]

Dependency Conflicts

NOTE: If you encounter issues related to org.slf4j:slf4j-api version conflicts, you can exclude the transitive SLF4J dependency and add a supported version explicitly:

implementation('com.trimble:trimble-id-android:1.2.0-alpha-20250620') {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation 'org.slf4j:slf4j-api:2.0.9'

Code snippets

Configure Authenticator

Authenticator class helps to authenticate users by exposing functionalities like Login, Logout, Retrieve Access Token, Retrieve User Information and Know a Logged in state. It implements IAuthenticator interface. Redirect uri for login and logout needs to be constructed using the Custom URI Scheme. Once the user is authenticated , authorization state of the user is store in shared preference for easy persistence. Shared preference also gets updated when tokens are refreshed and gets cleared on logout.

NOTE: It is recommended to use single instance of Authenticator across the application.

val authenticator = Authenticator(
context = context, // Context to handle authentication of user.
configurationEndpoint = "/.well-known/openid-configuration", // OpenID well known configuration endpoint
clientID = "clientID", // clientID of TID application
redirectUri = "redirectUri", // redirect uri
scope = "scope" // scope of TID application
)
.withPostLogoutRedirectUri("your-redirect-uri")

Redirect uri needs to be constructed using a Custom Uri Scheme.

Performing Login

Login method helps to authenticate the user. It discovers endpoints to interact with the provider, authorizes the user, via a browser to obtain an authorization code and exchanges the authorization code to obtain a refresh token and/or ID token. It persists authorization state of the user in an Encrypted SharedPreference as default. Result of login will be handled by registerLoginLauncher method. RegisterLoginLauncher needs to be invoked in the onCreate() or onStart() of the LifecycleOwner. It should be invoked before login method.

authenticator.registerLoginLauncher(context)

The context passed in registerLoginLauncher needs to be of type AppCompactActivity.

When the user completes login, result is sent to the end application via ILoginResponseCallback. Here Result can be either true for successful login or false for any exception.

authenticator.login(object : ILoginResponseCallback {
override fun onLoginCompleted(loginResult: Result<Boolean>) { //The result of login will be sent to the provided callback handler
loginResult.onSuccess {
//write the logic when Login is complete and success
}
loginResult.onFailure {
//write the logic when Login is complete but failed
}
}
}, launchAsTrustedWebActivity, forceNewLogin = true) // For multi-user scenarios, set forceNewLogin to true

NOTE:

  • Allows to browse the login page as a Trusted Web Activity. This can be achieved by setting launchAsTrustedWebActivity = true in login method. By default value is set to false. (Optional parameter)
  • For multi-user scenarios, it is recommended to set forceNewLogin = true to bypass Single Sign-On (SSO)

Retrieving an access token

To retrieve access token, invoke getAccessToken() method on the authenticator instance. It retrieves access token of authenticated user.

val accessToken = authenticator.getAccessToken()

Return value is either of type string or null. It returns null if access tokens is not valid or user is not authenticated. In such a scenario, perform login to continue.

NOTE: When the user is offline and offline mode is enabled, this method provides an offline token which is an encoded form of user id/sub and client id.

Retrieving User Info

To retrieve user information, invoke getUserInfo() method on the authenticator instance. It returns user info of authenticated user by parsing the idToken.

val user = authenticator.getUserInfo()

Return value is either of type User or null. Returns null if tokens are not valid or user is not authenticated. In such a scenario, perform login to continue.

To know the current logged-in state

Check whether the user is logged in, isLoggedIn() method can be used.

val isLoggedIn = authenticator.isLoggedIn()

Return value is true if a user is logged in and tokens are valid else false.

Performing Logout

Logout method ends a logged in session. It also clears the shared preference. To handle the result of logout, RegisterLogoutLauncher needs to be invoked before logout method is invoked. RegisterLogoutLauncher needs to be invoked in the onCreate() or onStart() of the LifecycleOwner.

authenticator.registerLogoutLauncher(context)

The context passed in registerLogoutLauncher needs to be of type AppCompactActivity.

When the user completes logout, result is sent to the end application via ILogoutResponseCallback. Here Result can be either true for successful logout or false for any exception.

authenticator.logout(object : ILogoutResponseCallback {
override fun onLogoutCompleted(logoutResult: Result<Boolean>) {
logoutResult.onSuccess {
// write the logic when logout is complete and success
}.onFailure {
// write the logic when logout is complete but failed
}
}
})

Offline Support

The Trimble Identity OAuth Android Library supports offline mode, allowing users to authenticate without an internet connection. Use withOfflineMode() to configure the Authenticator for offline authentication. Once configured with offline mode, the SDK automatically handles both online and offline scenarios

Key Features of Offline Authentication:

  • Passkey-based Authentication: Uses secure passkeys for offline login
  • Initial Online Requirement: Users must authenticate online at least once using passkey before offline mode becomes available
  • Secure Token Storage: Maintains secure token storage for offline access
  • Network Independence: Works completely without internet connectivity once configured
val authenticator = Authenticator(
context = context,
configurationEndpoint = "/.well-known/openid-configuration",
clientID = "clientID",
redirectUri = "redirectUri",
scope = "scope"
).withOfflineMode()

Multi-User Account Management

The MultiUserAccountManager class is responsible for managing user accounts in a multi-user environment. It interacts with the Authenticator instance to handle authentication-related tasks.

Capabilities

  • Maximum Accounts: The maximum number of accounts that can be added is 5
  • Automatic Management: If the limit is reached, the least recently used (LRU) account will be removed automatically when a new account is added
  • Force Login Recommendation: For multi-user scenarios, it is recommended to use the login method with forceNewLogin set to true to bypass Single Sign-On (SSO)
  • Required Setup: Before using switchAccount, login, or addAccount, you must call authenticator.registerLoginLauncher(AppCompatActivity) to handle the result of these operations

Initialize MultiUserAccountManager

To use MultiUserAccountManager, you need to initialize it with an instance of Authenticator:

val authenticator = Authenticator(
context = applicationContext,
configurationEndpoint = "/.well-known/openid-configuration",
clientID = "client-id",
redirectUri = "redirect-uri",
scope = "scope"
).withOfflineMode()
.withPostLogoutRedirectUri("your-redirect-uri")
val accountManager = MultiUserAccountManager(authenticator)

Add a New Account

Adds a new account. Before invoking this method, ensure that registerLoginLauncher of the Authenticator is called to handle the callback for the account add operation.

// Register the launcher first
authenticator.registerLoginLauncher(context)
// Add account
accountManager.addAccount(object : ILoginResponseCallback {
override fun onLoginCompleted(result: Result<Boolean>) {
result.onSuccess {
//write the logic when add account is complete and success
}.onFailure {
//write the logic when add account is complete but failed
}
}
}, launchAsTrustedWebActivity = false)

Switch to an Existing Account

Switches to an existing account. Before invoking this method, ensure that registerLoginLauncher of the Authenticator is called to handle the callback for the account switch operation.

// Register the launcher first
authenticator.registerLoginLauncher(context)
// Switch account
accountManager.switchAccount("account-id", object : ILoginResponseCallback {
override fun onLoginCompleted(result: Result<Boolean>) {
result.onSuccess {
//write the logic when switch account is complete and success
}.onFailure {
//write the logic when switch account is complete but failed
}
}
}, launchAsTrustedWebActivity = false)

Get All Logged-in Accounts

Retrieves a list of all stored accounts:

val accounts: List<Account> = accountManager.getAccounts()

Remove an Account

Removes a specific account by its identifier:

val result: Boolean = accountManager.removeAccount("account-id")

Returns true if the account was successfully removed, false otherwise.

Get Current Active Account

Retrieves the currently active account:

val activeAccount: Account = accountManager.getActiveAccount()

Check if More Accounts Can Be Added

Check if more accounts can be added:

val canAdd: Boolean = accountManager.canAddAccounts()

Returns true if more accounts can be added, false otherwise.

FAQ

Do you have questions? Do not worry, we have prepared a complete FAQ answering the most common questions.