Embedded Wallet SDK for Android
Overview
The Web3Auth by MetaMask, Embedded Wallet SDK provides authentication for Android applications with social sign-in, external wallets, and more. Our Android SDK, written in Kotlin, simplifies how you connect users to their preferred wallets and manage authentication state natively.
Requirements
- Android API version
26or newer - Android Compile and Target SDK:
34 - Basic knowledge of Java or Kotlin development
Prerequisites
- Set up your project on the Embedded Wallets dashboard.
See the dashboard setup guide to learn more.
Installation
Install the Web3Auth Android SDK by adding it to your project dependencies:
1. Add JitPack repository
In your project-level Gradle file add JitPack repository:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url "https://jitpack.io" } // <-- Add this line
}
}
2. Add Web3Auth dependency
Then, in your app-level build.gradle dependencies section, add the following:
dependencies {
// ...
implementation 'com.github.web3auth:web3auth-android-sdk:11.0.1'
}
2.1. Update permissions
Open your app's AndroidManifest.xml file and add the following permission. Ensure the <uses-permission> element is a direct child of the <manifest> root element.
<uses-permission android:name="android.permission.INTERNET" />
2.2 Configure AndroidManifest.xml File
Ensure your main activity launchMode is set to singleTop in your AndroidManifest.xml:
<activity
android:launchMode="singleTop"
android:name=".YourActivity">
// ...
</activity>
From version 7.1.2, set android:allowBackup to false and add tools:replace="android:fullBackupContent" in your AndroidManifest.xml file:
<application
android:allowBackup="false"
tools:replace="android:fullBackupContent"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher">
</application>
3. Handle redirects
Once the Gradle files and permissions have been updated, you need to configure your Embedded Wallets project by allowlisting your scheme and package name.
Configure a Plug n Play project
- From the Embedded Wallets dashboard, create or open an existing Web3Auth project.
- Allowlist
{SCHEME}://{YOUR_APP_PACKAGE_NAME}in the dashboard. This step is mandatory for the redirect to work.
Configure deep link
Open your app's AndroidManifest.xml file and add the following deep link intent filter to your main activity:
<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="{scheme}" android:host="{YOUR_APP_PACKAGE_NAME}"/>
<!-- Accept URIs: w3a://com.example.w3aflutter -->
</intent-filter>
4. Triggering sign-in exceptions
The Android SDK uses the custom tabs and from current implementation of Chrome custom tab, it's not possible to add a listener directly to Chrome custom tab close button and trigger sign-in exceptions.
Apply the setCustomTabsClosed method in your sign-in screen to trigger sign-in exceptions for Android.
class MainActivity : AppCompatActivity() {
// Additional code
override fun onResume() {
super.onResume()
if (Web3Auth.getCustomTabsClosed()) {
Toast.makeText(this, "User closed the browser.", Toast.LENGTH_SHORT).show()
web3Auth.setResultUrl(null)
Web3Auth.setCustomTabsClosed(false)
}
}
// Additional code
}
Initialize Embedded Wallets
1. Create an Embedded Wallets instance
Create an Embedded Wallets instance and configure it with your project settings:
import com.web3auth.core.Web3Auth
import com.web3auth.core.types.Web3AuthOptions
import org.torusresearch.fetchnodedetails.types.Web3AuthNetwork
var web3Auth = Web3Auth(
Web3AuthOptions(
clientId = "YOUR_WEB3AUTH_CLIENT_ID", // Pass over your Web3Auth Client ID from Developer Dashboard
web3AuthNetwork = Web3AuthNetwork.SAPPHIRE_MAINNET, // or Web3AuthNetwork.SAPPHIRE_DEVNET
redirectUrl = "{YOUR_APP_PACKAGE_NAME}://auth",
),
this
)
// Handle user signing in when app is in background
web3Auth.setResultUrl(intent?.data)
2. Set result URL
Whenever user initiates a sign-in flow, a new intent of CustomTabs is launched. It's necessary step to use setResultUrl in onNewIntent method to successful track the sign-in process.
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
// Handle user signing in when app is active
web3Auth.setResultUrl(intent.data)
}
3. Initialize the Embedded Wallets instance
After instantiating Embedded Wallets, call the initialize method. This method fetches your project configuration from the dashboard (whitelabel, chains, MFA settings, and session time) and restores any existing session.
initialize completes successfully only when it restores an active session. If there is no saved session, or the saved session is invalid or expired, the returned CompletableFuture completes exceptionally and the SDK clears the stored session data. It also completes exceptionally if fetching the project configuration fails.
A failed initialize call usually means the user isn't signed in. Show your sign-in screen in the error branch.
If you need to distinguish the cases, the no-session error message is No user found, please login again!.
val initializeCF: CompletableFuture<Void> = web3Auth.initialize()
initializeCF.whenComplete { _, error ->
if (error == null) {
// Active session restored
val privateKey = web3Auth.getPrivateKey()
} else {
// No active session, or initialization failed. Show the sign-in screen.
Log.d("MainActivity_Web3Auth", error.message ?: "Something went wrong")
}
}
Advanced configuration
The Web3Auth Android SDK offers a rich set of advanced configuration options:
- Custom authentication: Define authentication methods.
- Whitelabeling and UI customization: Personalize the modal's appearance.
- Multi-Factor Authentication (MFA): Set up and manage MFA.
- Dapp Share: Share dapp sessions across devices.
See the advanced configuration sections to learn more about each configuration option.
- Basic Configuration
- Advanced Configuration
val web3Auth = Web3Auth(
Web3AuthOptions(
clientId = "YOUR_CLIENT_ID",
web3AuthNetwork = Web3AuthNetwork.SAPPHIRE_MAINNET, // or Web3AuthNetwork.SAPPHIRE_DEVNET
redirectUrl = "YOUR_APP_SCHEME://auth"
),
this
)
val web3Auth = Web3Auth(
Web3AuthOptions(
clientId = "YOUR_CLIENT_ID",
web3AuthNetwork = Web3AuthNetwork.SAPPHIRE_MAINNET, // or Web3AuthNetwork.SAPPHIRE_DEVNET
redirectUrl = "YOUR_APP_SCHEME://auth",
authConnectionConfig = listOf(AuthConnectionConfig(
authConnectionId = "auth-connection-id", // Get it from MetaMask Developer Dashboard
authConnection = AuthConnection.GOOGLE,
clientId = getString(R.string.google_client_id) // Google's client id
)),
mfaSettings = MfaSettings(
deviceShareFactor = MfaSetting(true, 1, true),
socialBackupFactor = MfaSetting(true, 2, true),
passwordFactor = MfaSetting(true, 3, false),
backUpShareFactor = MfaSetting(true, 4, false),
passkeysFactor = MfaSetting(true, 5, true),
authenticatorFactor = MfaSetting(true, 6, true),
)
),
this
)
Single Factor Auth (SFA) Support
Web3Auth Android SDK includes built-in support for Single Factor Auth (SFA), allowing for seamless authentication when you already have a JWT token from your authentication system. Users are authenticated using just your JWT token, without a browser sign-in flow.
// SFA sign-in with custom JWT
val loginCompletableFuture = web3Auth.connectTo(
LoginParams(
AuthConnection.CUSTOM,
authConnectionId = "your_auth_connection_id",
idToken = "your_jwt_token"
)
)
SFA mode is automatically activated when you provide an idToken parameter. This enables direct authentication without additional social sign-in steps, perfect for applications that already have their own authentication system.
connectToin SFA mode retrieves key shares with blocking network calls on the calling thread. Call it from a background thread (for example,Dispatchers.IOor anExecutor), not the main thread.- If the user has already enabled MFA, SFA sign-in fails with
User has already enabled MFA. Sign these users in through the browser flow instead, by passing the JWT asextraLoginOptions = ExtraLoginOptions(id_token = jwt)without settingidToken. enableMFA()andmanageMFA()aren't available for SFA sessions and fail withEnabling MFA is not allowed for this user.- SFA sessions are stored in the session service, not as Auth tokens.
getAccessToken()andgetIdentityToken()aren't available for SFA sessions.
Blockchain Integration
Embedded Wallets is blockchain agnostic, enabling integration with any blockchain network. Out of the box, Embedded Wallets offers robust support for both Solana and Ethereum.
Ethereum integration
For Ethereum integration, you can get the private key using the getPrivateKey method and use it with web3j or other Ethereum libraries:
import org.web3j.crypto.Credentials
import org.web3j.protocol.core.DefaultBlockParameterName
import org.web3j.protocol.Web3j
import org.web3j.protocol.http.HttpService
// Use your Web3Auth instance to get the private key
val privateKey = web3Auth.getPrivateKey()
// Generate the Credentials
val credentials = Credentials.create(privateKey)
// Get the address
val address = credentials.address
// Create the Web3j instance using your RPC URL
val web3 = Web3j.build(HttpService("YOUR_RPC_URL"))
// Get the balance
val balanceResponse = web3.ethGetBalance(address, DefaultBlockParameterName.LATEST).send()
// Convert the balance from Wei to Ether format
val ethBalance = BigDecimal.valueOf(balanceResponse.balance.toDouble()).divide(BigDecimal.TEN.pow(18))
Solana integration
For Solana integration, you can get the Ed25519 private key using the getEd25519PrivateKey method and use it with sol4k or any other Solana libraries:
import org.sol4k.Connection
import org.sol4k.Keypair
val connection = Connection(RpcUrl.DEVNET)
// Use your Web3Auth instance to get the private key
val ed25519PrivateKey = web3Auth.getEd25519PrivateKey()
// Generate the Solana KeyPair
val solanaKeyPair = Keypair.fromSecretKey(ed25519PrivateKey.hexToByteArray())
// Get the user's public key
val publicKey = solanaKeyPair.publicKey.toBase58()
// Get the user balance
val userBalance = connection.getBalance(publicKey).toBigDecimal()