📚 Documentation • 🚀 Getting Started • 💻 Sample App • 💬 Feedback
Composable UI building blocks for MFA enrollment and verification on Android, built with Jetpack Compose. This library provides ready-to-use components that integrate seamlessly with Auth0's authentication flows.
This library provides ready-to-use UI components for multi-factor authentication:
- 🔐 TOTP (Time-based One-Time Password) - Authenticator app support with QR code enrollment
- 📱 Push Notifications - Secure push-based authentication
- 💬 SMS OTP - Phone number verification via one-time codes
- 📧 Email OTP - Email-based verification
- 🔑 Recovery Codes - Backup authentication codes for account recovery
All components are built on top of the Auth0 Android SDK and integrate with Auth0's My Account APIs.
⚠️ My Account APIs Required - This SDK requires My Account APIs which are currently in early access. Please reach out to Auth0 support to enable My Account APIs for your tenant.
⚠️ BETA RELEASE - This SDK is currently in beta. APIs may change before the stable release.
Android API version 30 or later and Java 17+.
Here's what you need in build.gradle to target Java 17 byte code for Android and Kotlin plugins respectively:
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
}Build Configuration:
- Gradle 8.13+ with AGP 8.11+
- Kotlin 2.2.20
- Jetpack Compose
Add the dependency to your build.gradle file:
dependencies {
implementation 'com.auth0.universalcomponents:universal-components:1.0.0'
}Using Version Catalog
Add to your gradle/libs.versions.toml:
[versions]
auth0-universal-components = "1.0.0"
[libraries]
auth0-universal-components = { module = "com.auth0.universalcomponents:universal-components", version.ref = "auth0-universal-components" }Then in your build.gradle:
dependencies {
implementation(libs.auth0.universal.components)
}Open your app's AndroidManifest.xml file and add the following permission:
<uses-permission android:name="android.permission.INTERNET" />First, create an instance of Auth0 with your Application information:
val account = Auth0.getInstance("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}")Configure using Android Context
Alternatively, you can save your Application information in the strings.xml file using the following names:
<resources>
<string name="com_auth0_client_id">YOUR_CLIENT_ID</string>
<string name="com_auth0_domain">YOUR_DOMAIN</string>
</resources>You can then create a new Auth0 instance by passing an Android Context:
val account = Auth0.getInstance(context)Go to the Auth0 Dashboard and navigate to your application's settings. Make sure you have the following:
- Application Type: Set to Native
- Allowed Callback URLs: Add a URL with the following format:
https://{YOUR_AUTH0_DOMAIN}/android/{YOUR_APP_PACKAGE_NAME}/callback
Replace {YOUR_APP_PACKAGE_NAME} with your actual application's package name, available in your app/build.gradle file as the applicationId value.
Next, define the Manifest Placeholders for the Auth0 Domain and Scheme. Go to your application's build.gradle file and add the manifestPlaceholders line:
android {
defaultConfig {
applicationId "com.auth0.android.sample"
minSdk 30
targetSdk 36
// Add these manifest placeholders
manifestPlaceholders = [
auth0Domain: "@string/com_auth0_domain",
auth0Scheme: "@string/com_auth0_scheme"
]
}
}Note: The scheme value can be either
httpsor a custom one. See App Deep Linking for more details.
Initialize the Auth0 Universal Components library in your Application class or main Activity:
// Create Auth0 account instance
val account = Auth0.getInstance(clientId, domain)
// Setup credentials manager
val credentialsManager = CredentialsManager(
AuthenticationAPIClient(account),
SharedPreferencesStorage(context)
)
// Initialize the UI library
Auth0UniversalComponents.initialize(
account = account,
tokenProvider = DefaultTokenProvider(credentialsManager),
scheme = "https"
)In your Compose UI, simply add the MFA component where you want users to manage their multi-factor authentication:
@Composable
fun SettingsScreen() {
MFAComponent()
}Navigation between different MFA enrollment and verification flows is handled internally by the library.
Advanced Configuration
For advanced configurations:
// Custom token provider
class CustomTokenProvider : TokenProvider {
override suspend fun getAccessToken(): String {
// Your custom logic to retrieve access token
return credentialsManager.awaitCredentials().accessToken
}
}
// Initialize with custom configuration
Auth0UniversalComponents.initialize(
account = account,
tokenProvider = CustomTokenProvider(),
scheme = "customscheme"
)Ensure you're using:
- Kotlin 2.2.20
- Jetpack Compose
- Java 17
Whenever possible, Auth0 recommends using Android App Links as a secure way to link directly to content within your app. Custom URL schemes can be subject to client impersonation attacks.
If you followed the configuration steps above, the default scheme is https. This works best for Android API 23 or newer with Android App Links, but on older Android versions, this may show an intent chooser dialog. You can use a custom unique scheme instead:
- Update the
auth0SchemeManifest Placeholder in yourapp/build.gradlefile - Update the Allowed Callback URLs in your Auth0 Dashboard
- Pass your custom scheme when initializing:
Auth0UniversalComponents.initialize(
account = account,
tokenProvider = tokenProvider,
scheme = "customscheme"
)Note that schemes can only have lowercase letters.
This repository includes a complete sample application demonstrating the MFA UI components in action.
Use the bootstrap script to automatically create all required Auth0 resources and configure the sample app.
Prerequisites:
-
Login to Auth0 CLI with the required scopes:
auth0 login --scopes "create:client_grants,update:client_grants,delete:client_grants,create:connections,create:resource_servers,create:roles,create:users,read:client_keys,read:client_grants,read:clients,read:connections,read:resource_servers,read:roles,update:clients,update:connections,read:connection_profiles,create:connection_profiles,update:connection_profiles,create:user_attribute_profiles,update:user_attribute_profiles,read:user_attribute_profiles,update:resource_servers,update:roles,update:tenant_settings,update:prompts" auth0 tenants list # verify your tenant shows Active
-
Run the bootstrap script:
cd app/scripts npm install npm run auth0:bootstrap <your-tenant-domain>
This will:
- Create a Native application configured for the Android sample app
- Enable the My Account API and create a Client Grant with MFA scopes
- Create a database connection and admin role
- Configure tenant settings for MFA
- Update
strings.xmlwith the generated credentials
-
Create a Native application in your Auth0 tenant and note the Client ID and Domain.
-
Configure Allowed Callback URLs in your Auth0 Dashboard. Add:
{scheme}://{domain}/android/com.auth0.android.sample/callbackReplace
{scheme}and{domain}with your values. -
Set your Auth0 credentials in
app/src/main/res/values/strings.xml:<resources> <string name="com_auth0_client_id">YOUR_CLIENT_ID</string> <string name="com_auth0_domain">YOUR_DOMAIN</string> <string name="com_auth0_scheme">demo</string> </resources>
From Android Studio:
- Open the project folder
- Let Gradle sync finish
- Select the
apprun configuration - Click Run on a device/emulator (API 30+)
From Terminal:
./gradlew :app:installDebugThis installs the debug build on a connected device/emulator. You can also assemble APKs:
./gradlew :app:assembleDebug- Login Screen - Launch the app to see the login interface
- Universal Login - Tap Login to authenticate via Auth0's Universal Login in the browser
- MFA Settings - After successful login, you'll see the MFA management interface where you can:
- View all available MFA methods
- Enroll TOTP authenticators via QR code
- Configure Push notifications
- Set up SMS or Email verification
- Generate and manage Recovery Codes
Browser returns to the app but nothing happens
- Verify your scheme/domain in
strings.xmlmatch the Auth0 Allowed Callback URL exactly - Example:
demo://your-tenant.us.auth0.com/android/com.auth0.android.sample/callback - Check that the
manifestPlaceholdersinbuild.gradleare correctly configured - Ensure the
auth0Schemematches what you're using in the initialization
Login completes but API calls fail (401/403)
- Confirm the audience and scopes are correctly configured
- Verify your application is authorized to call the MyAccount APIs
- Check that you're requesting the
offline_accessscope for refresh tokens - Ensure the access token is being properly stored and retrieved
SMS/Email OTP not received
- Verify that SMS/Email factors are enabled in your Auth0 tenant Dashboard
- Check that you've configured the appropriate SMS/Email providers in Auth0
- Confirm the test device phone number or email is valid and reachable
- Check spam folders for email OTPs
Build errors or dependency conflicts
- Ensure you're using the correct versions:
- JDK 17
- AGP 8.11+
- Gradle 8.13+
- Kotlin 2.2.20
- Clear Gradle cache:
./gradlew clean - Invalidate caches in Android Studio: File → Invalidate Caches / Restart
We appreciate feedback and contribution to this repo! Before you get started, please see the following:
To provide feedback or report a bug, please raise an issue on our issue tracker.
Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.
Portions of this SDK may have AI-assisted or generated code.

Auth0 is an easy-to-implement, adaptable authentication and authorization platform. To learn more check out Why Auth0?
This project is licensed under the Apache License 2.0. See the LICENSE file for more info.
Copyright 2025 Okta, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
