Android
Overview
The LoginID Android SDK enables you to add passkey authentication in your native Android application without having to redirect the user to any pages outside your application.
The SDK leverages the Credential Manager API for creating and syncing passkeys with Google Password Manager.
Requirements
- Android 9+ (API level 28+)
- Android Studio
- Kotlin
Prerequisites
- Create an application to obtain a base URL. The SDK uses this base URL to interact with the LoginID authentication service.
- Create an API key with at least the external:verify scope. You’ll need this to request authorization tokens from your backend.
Before installing the SDK, configure the association between your Android application and your website using a Digital Asset Links file.
Configure Digital Asset Links
Android uses a Digital Asset Links file named assetlinks.json to verify the association between your application and your website.
Find Your Package Name
You can find your application's package name in the app module's build.gradle.kts file under defaultConfig:
android {
defaultConfig {
applicationId = "<PACKAGE_NAME>"
}
}
Generate the SHA-256 Certificate Fingerprint
Use the keytool utility included with the Java Development Kit to retrieve the SHA-256 fingerprint of your application's signing certificate:
keytool -list -v \
-keystore KEYSTORE_PATH \
-alias KEYSTORE_ALIAS \
-storepass KEYSTORE_PASSWORD \
-keypass KEY_PASSWORD
Replace the following values:
KEYSTORE_PATHwith the path to your keystoreKEYSTORE_ALIASwith the signing-key aliasKEYSTORE_PASSWORDwith the keystore passwordKEY_PASSWORDwith the signing-key password
The command output includes the certificate's SHA-256 fingerprint.
For local development, you can use the default Android debug keystore with the following values:
KEYSTORE_ALIAS:androiddebugkeyKEYSTORE_PASSWORD:androidKEY_PASSWORD:android
Use a dedicated signing key for production applications. For applications distributed through Google Play, you can find the app-signing certificate fingerprint in the Google Play Console.
Register the Fingerprint
Register your application's SHA-256 certificate fingerprint in your LoginID application's FIDO2 section before continuing. For instructions, see Adding Android Fingerprint.
Host the assetlinks.json File
Create an assetlinks.json file containing your application's package name and SHA-256 certificate fingerprint:
[
{
"relation": [
"delegate_permission/common.get_login_creds"
],
"target": {
"namespace": "android_app",
"package_name": "<PACKAGE_NAME>",
"sha256_cert_fingerprints": [
"<SHA256_FINGERPRINT>"
]
}
}
]
Replace <PACKAGE_NAME> and <SHA256_FINGERPRINT> with your application's values.
Host the file at the following location:
https://<WEBSITE_DOMAIN>/.well-known/assetlinks.json
The file must be publicly accessible over HTTPS.
Declare the Association in Your Android Application
Add an asset_statements resource to res/values/strings.xml:
<resources>
<string name="asset_statements" translatable="false">
[{
\"include\": \"https://<WEBSITE_DOMAIN>/.well-known/assetlinks.json\"
}]
</string>
</resources>
Then add the corresponding <meta-data> element inside the <application> element of your AndroidManifest.xml file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<meta-data
android:name="asset_statements"
android:resource="@string/asset_statements" />
</application>
</manifest>
Set Up the SDK
Download the SDK
After creating your LoginID application, open the Android section of the Get Started guide and download the latest version of the SDK.
The SDK is distributed as Android Archive (.aar) files.
Add the SDK to Your Project
Copy the LoginID SDK artifacts into your app module's libs directory:
app/
└── libs/
├── api.jar
├── core-release.aar
└── auth-release.aar
Add the SDK artifacts and required dependencies to your app module's build.gradle.kts:
dependencies {
// LoginID SDK
implementation(files("libs/api.jar"))
implementation(files("libs/core-release.aar"))
implementation(files("libs/auth-release.aar"))
// Required dependencies
implementation("com.squareup.okhttp3:okhttp:5.1.0")
implementation("com.squareup.moshi:moshi:1.15.2")
implementation("com.squareup.moshi:moshi-adapters:1.15.2")
ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.2")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
implementation("androidx.credentials:credentials-play-services-auth:1.6.0")
implementation("androidx.security:security-crypto:1.1.0")
}
Initialize the SDK
- Kotlin
import com.loginid.core.models.LoginIDConfig
import com.loginid.mfa.LoginIDAuth
class MyApplication : Application() {
val lid = LoginIDAuth(<LOGINID_BASE_URL>)
override fun onCreate() {
super.onCreate()
// Additional setup...
}
}
Class LoginIDAuth
High-level entry point for LoginID authentication on Android.
This facade composes core SDK services to provide a simple API for:
- Creating and authenticating with passkeys
- Confirming transactions (non-repudiation)
- Requesting, sending, and validating one-time passwords (OTP)
- Managing passkeys (list, rename, delete)
- Inspecting and clearing the current session
- Verifying environment configuration
All public operations are exposed as suspend functions and should be called from a coroutine. Instances are lightweight and can be stored as a singleton in your application layer.
constructor
Initializes a new instance of the LoginIDAuth.
class LoginIDAuth(config: LoginIDConfig)
constructor(config: LoginIDConfig)
| Parameter | Type | Required | Description |
|---|---|---|---|
| config | LoginIDConfig | Yes | |
| config.context | Context | Yes | The Android application context. |
| config.baseUrl | String | Yes | The base URL of the LoginID service. This value is used to resolve the App ID and make API calls. |
| config.appId | String | No | The application ID. If not provided, it will be extracted from the baseUrl. |
| config.useTrustId | Boolean | No | A flag to enable or disable the use of Trust ID. Defaults to false. |
LoginIDAuth
constructor(context: Context, baseUrl: String)
Creates a new authentication helper using a base URL.
Use this initializer when you only have the environment base URL and want sensible defaults for the underlying SDK configuration.
| Parameter | Type | Required | Description |
|---|---|---|---|
| context | Context | Yes | The Android application context. |
| baseUrl | String | Yes | The LoginID environment base URL (e.g., from your environment configuration). |
LoginIDAuth
createPasskey
createPasskey(activity: Activity, username: String, options: CreatePasskeyOptions?)
This method helps to create a passkey. The only required parameter is the username, but additional attributes can be provided in the options parameter. Note: While the authorization token is optional, it must always be used in a production environment. You can skip it during development by adjusting the app configuration in the LoginID dashboard.
A short-lived authorization token is returned, allowing access to protected resources for the given user such as listing, renaming or deleting passkeys.
createPasskey(activity: Activity, username: String, options: CreatePasskeyOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| activity | Activity | Yes | The current activity. |
| username | String | Yes | The username for which to create the passkey. |
| options | CreatePasskeyOptions? | No | Optional parameters for passkey creation. |
| options.authzToken | String? | No | An optional authorization token used for accessing protected resources. |
| options.usernameType | UsernameType | No | The type of username validation to use. Defaults to UsernameType.OTHER. |
| options.displayName | String? | No | An optional human-readable name for the user account, displayed in passkeys and authentication prompts. |
| options.passkeyName | String? | No | An optional custom label or nickname for the passkey, useful for distinguishing between multiple passkeys. |
| options.deviceId | String? | No | An optional identifier for the device creating the passkey. Used to enable device-specific authentication flows and identify the device during future authentications. |
data class AuthResult(
val isAuthenticated: Boolean
val isFallback: Boolean
val fallbackOptions: FallbackMethodsResult?
val token: String?
val userId: String?
val passkeyId: String?
val deviceId: String?
)
createPasskey(activity: Activity, username: String, authzToken: String, options: CreatePasskeyOptions?)
This method helps to create a passkey. The only required parameter is the username, but additional attributes can be provided in the options parameter. Note: While the authorization token is optional, it must always be used in a production environment. You can skip it during development by adjusting the app configuration in the LoginID dashboard.
A short-lived authorization token is returned, allowing access to protected resources for the given user such as listing, renaming or deleting passkeys.
createPasskey(activity: Activity, username: String, authzToken: String, options: CreatePasskeyOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| activity | Activity | Yes | The current activity. |
| username | String | Yes | The username for which to create the passkey. |
| authzToken | String | Yes | An authorization token from a previous authentication step. |
| options | CreatePasskeyOptions? | No | Optional parameters for passkey creation. |
| options.authzToken | String? | No | An optional authorization token used for accessing protected resources. |
| options.usernameType | UsernameType | No | The type of username validation to use. Defaults to UsernameType.OTHER. |
| options.displayName | String? | No | An optional human-readable name for the user account, displayed in passkeys and authentication prompts. |
| options.passkeyName | String? | No | An optional custom label or nickname for the passkey, useful for distinguishing between multiple passkeys. |
| options.deviceId | String? | No | An optional identifier for the device creating the passkey. Used to enable device-specific authentication flows and identify the device during future authentications. |
data class AuthResult(
val isAuthenticated: Boolean
val isFallback: Boolean
val fallbackOptions: FallbackMethodsResult?
val token: String?
val userId: String?
val passkeyId: String?
val deviceId: String?
)
authenticateWithPasskey
authenticateWithPasskey(activity: Activity, username: String, options: AuthenticateWithPasskeyOptions?)
This method authenticates a user with a passkey and may trigger additional browser dialogs to guide the user through the process.
A short-lived authorization token is returned, allowing access to protected resources for the given user such as listing, renaming or deleting passkeys.
authenticateWithPasskey(activity: Activity, username: String, options: AuthenticateWithPasskeyOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| activity | Activity | Yes | The current activity. |
| username | String | Yes | The username of the user to authenticate. |
| options | AuthenticateWithPasskeyOptions? | No | Optional parameters for passkey authentication. |
| options.usernameType | UsernameType | No | The type of username validation to be used. Defaults to [UsernameType.OTHER]. |
| options.autofill | Boolean? | No | When true, enables passkey keyboard autofill suggestions. Username does not need to be set. |
data class AuthResult(
val isAuthenticated: Boolean
val isFallback: Boolean
val fallbackOptions: FallbackMethodsResult?
val token: String?
val userId: String?
val passkeyId: String?
val deviceId: String?
)
authenticateWithPasskeyAutofill
authenticateWithPasskeyAutofill(activity: Activity, usernameAnchorView: View, options: AuthenticateWithPasskeyOptions?)
Authenticates a user by utilizing the browser's passkey autofill capabilities.
A short-lived authorization token is returned, allowing access to protected resources for the given user such as listing, renaming or deleting passkeys.
authenticateWithPasskeyAutofill(activity: Activity, usernameAnchorView: View, options: AuthenticateWithPasskeyOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| activity | Activity | Yes | The current activity. |
| usernameAnchorView | View | Yes | The view to which the passkey selection UI should be anchored. This is typically a username input field. |
| options | AuthenticateWithPasskeyOptions? | No | Optional parameters for passkey authentication. |
| options.usernameType | UsernameType | No | The type of username validation to be used. Defaults to [UsernameType.OTHER]. |
| options.autofill | Boolean? | No | When true, enables passkey keyboard autofill suggestions. Username does not need to be set. |
data class AuthResult(
val isAuthenticated: Boolean
val isFallback: Boolean
val fallbackOptions: FallbackMethodsResult?
val token: String?
val userId: String?
val passkeyId: String?
val deviceId: String?
)
confirmTransaction
confirmTransaction(activity: Activity, username: String, txPayload: String, options: ConfirmTransactionOptions?)
This method initiates a non-repudiation signature process by generating a transaction-specific challenge and then expects the client to provide an assertion response using a passkey.
This method is useful for confirming actions such as payments or changes to sensitive account information, ensuring that the transaction is being authorized by the rightful owner of the passkey.
For a more detailed guide click here.
confirmTransaction(activity: Activity, username: String, txPayload: String, options: ConfirmTransactionOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| activity | Activity | Yes | The current activity. |
| username | String | Yes | The username of the account holder confirming the transaction. |
| txPayload | String | Yes | A string representing the transaction details, such as an amount or action. |
| options | ConfirmTransactionOptions? | No | Optional parameters to customize the transaction, like providing a nonce or specifying the txType. |
| options.nonce | String? | No | A unique nonce to ensure the transaction's integrity and prevent replay attacks. If not provided, a new UUID will be generated. |
| options.txType | String? | No | The type of transaction payload, such as raw or a custom format. Defaults to raw if not specified. |
data class TxConfirmResult(
val token: String
val credentialId: String
val passkey: PasskeyDetails?
)
renamePasskey
renamePasskey(id: String, name: String, options: RenamePasskeyOptions?)
Renames a specified passkey by ID. The user must be fully authorized for this call to succeed.
renamePasskey(id: String, name: String, options: RenamePasskeyOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | String | Yes | The unique identifier of the passkey to rename. |
| name | String | Yes | The new name for the passkey. |
| options | RenamePasskeyOptions? | No | Options for the request, including an optional authorization token. |
| options.authzToken | String | Yes | An authorization token from a previous authentication step. |
renamePasskey(id: String, name: String, authzToken: String)
Renames a specified passkey by ID. The user must be fully authorized for this call to succeed.
renamePasskey(id: String, name: String, authzToken: String)
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | String | Yes | The unique identifier of the passkey to rename. |
| name | String | Yes | The new name for the passkey. |
| authzToken | String | Yes | Authorization token. |
deletePasskey
deletePasskey(id: String, options: DeletePasskeyOptions?)
Delete a specified passkey by ID from LoginID. The user must be fully authorized for this call to succeed.
deletePasskey(id: String, options: DeletePasskeyOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | String | Yes | The unique identifier of the passkey to delete. |
| options | DeletePasskeyOptions? | No | Options for the request, including an optional authorization token. |
| options.authzToken | String | Yes | An authorization token from a previous authentication step. |
deletePasskey(id: String, authzToken: String)
Delete a specified passkey by ID from LoginID. The user must be fully authorized for this call to succeed.
deletePasskey(id: String, authzToken: String)
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | String | Yes | The unique identifier of the passkey to delete. |
| authzToken | String | Yes | Authorization token. |
requestOtp
requestOtp(options: RequestOtpOptions?)
This method returns a one-time OTP to be displayed on the current device. The user must be authenticated on this device. The OTP is meant for cross-authentication, where the user reads the OTP from the screen and enters it on the target device.
requestOtp(options: RequestOtpOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| options | RequestOtpOptions? | No | Options for the request, including an optional authorization token. |
| options.authzToken | String? | No | An optional authorization token for the request. If not provided, the SDK will use a stored token if available. |
data class OTPResult(
val code: String
val expiresAt: String
)
validateOtp
validateOtp(username: String, otp: String, options: ValidateOtpOptions?)
This method verifies the OTP and returns an authorization token, which can be used with the createPasskey()
method to create a new passkey. The authorization token has a short validity period and should be used immediately.
validateOtp(username: String, otp: String, options: ValidateOtpOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| username | String | Yes | The username of the account being authenticated. |
| otp | String | Yes | The one-time password entered by the user. |
| options | ValidateOtpOptions? | No | Optional parameters to customize the request, such as usernameType. |
| options.usernameType | UsernameType | No | The type of username validation to be used. Defaults to .OTHER. |
data class AuthResult(
val isAuthenticated: Boolean
val isFallback: Boolean
val fallbackOptions: FallbackMethodsResult?
val token: String?
val userId: String?
val passkeyId: String?
val deviceId: String?
)
requestAndSendOtp
requestAndSendOtp(username: String, method: MessageMethod, options: RequestAndSendOtpOptions?)
This method requests an OTP from the backend to be sent via the selected method. The method of delivery should be based on
the user's choice from the list of available options. This can be found in the result of authenticateWithPasskey
method as fallbackOptions.
requestAndSendOtp(username: String, method: MessageMethod, options: RequestAndSendOtpOptions?)
| Parameter | Type | Required | Description |
|---|---|---|---|
| username | String | Yes | The username to send the OTP to. |
| method | EMAILSMS | No | The delivery channel, either EMAIL or SMS. Defaults to EMAIL. |
| options | RequestAndSendOtpOptions? | No | Optional parameters to customize the request, such as usernameType. |
| options.usernameType | UsernameType | No | The type of username validation to be used. Defaults to .OTHER. |
verifyConfigSettings
verifyConfigSettings()
Validates the application's configuration settings and provides a suggested correction if any issues are detected.
verifyConfigSettings()
data class LoginIDConfigResult(
val solution: String
val code: String
val errorMessage: String
)
getSessionInfo
getSessionInfo()
Check whether the user of the current session is authenticated and returns user info. This info is retrieved locally and no requests to backend are made.
getSessionInfo()
data class SessionInfo(
val username: String
val id: String
val rpId: String
)
logout
logout()
Clears current user session. This method deletes the authorization token locally.
logout()
Errors
LoginIDError
Can occur during the authentication process. It is designed to encapsulate detailed information about login-related errors, making it easier to handle and debug issues related to user authentication.
| Field | Type | Details |
|---|---|---|
| msgCode | string | The error code associated with the login error. Defaults to unknown_error. |
| msg | string | The detailed message or description of the error. Defaults to unknown error. |
| messgage | string | The detailed message or description of the error. Defaults to unknown error. |
...
...
} catch (error: Exception) {
if (error is LoginIDError) {
print("Failed with error: ${error.msg}")
print("Failed with error code: ${error.msgCode}")
}
}