> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticate with External Wallets

> Let users sign in to your Android app with wallets they already own, such as MetaMask or Phantom.

External wallets — also called externally owned accounts (EOAs) — are wallets users bring to your app, such as MetaMask, Phantom, or Rainbow. They are different from embedded wallets, which Dynamic creates and manages for the user.

When external wallet login is enabled, users can sign up or log in by connecting an existing wallet through the Dynamic auth UI. The SDK handles the wallet app handoff and returns the connected wallet.

## Prerequisites

* Dynamic Kotlin SDK initialized (see [Quickstart](/docs/kotlin/quickstart))
* `DynamicUI` included in your Compose layout
* `ClientProps` configured with `appOrigin` and `redirectUrl`
* Chains enabled in your Dynamic dashboard
* Wallet login enabled under **External Wallets** in the dashboard

## Dashboard configuration

1. Go to **Chains & Networks** in the [Dynamic dashboard](https://app.dynamic.xyz/dashboard/chains-and-networks) and enable the chains you want to support (e.g. EVM, Solana).
2. Go to **Log in & User Profile** in the [Dynamic dashboard](https://app.dynamic.xyz/dashboard/log-in-user-profile) and toggle on **Wallet Log in** under **External Wallets**.
3. Go to **Security → Whitelist Mobile Deeplink** and add the same URL you use for `redirectUrl` (e.g. `myapp://`). This is required for the wallet app to return to your app after approval.

<Warning>
  `appOrigin` is required for external wallet connections. Use the HTTPS origin that represents your app (for example, `https://your-app.com`).
</Warning>

## SDK configuration

Make sure `ClientProps` includes `appOrigin` and `redirectUrl` when you initialize the SDK:

```kotlin theme={"system"}
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.core.ClientProps

val props = ClientProps(
    environmentId = "your-environment-id",
    appName = "My App",
    appLogoUrl = "https://your-app.com/logo.png",
    appOrigin = "https://your-app.com",
    redirectUrl = "myapp://"
)

DynamicSDK.initialize(props, applicationContext, this)
```

## Deep link setup

External wallet connections open the wallet app using deep links. The wallet app then redirects back to your app using the `redirectUrl` you configured.

The SDK includes `AuthCallbackActivity` to handle OAuth and wallet redirects. Add the intent filter in `android/app/src/main/AndroidManifest.xml`:

```xml theme={"system"}
<activity
    android:name="com.dynamic.sdk.android.Auth.AuthCallbackActivity"
    android:exported="true"
    android:launchMode="singleTop"
    android:noHistory="true"
    android:theme="@android:style/Theme.Translucent.NoTitleBar">
    <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="myapp" />
    </intent-filter>
</activity>
```

The `android:scheme` must match the scheme in `redirectUrl`. For example, if `redirectUrl = "myapp://"`, use `android:scheme="myapp"`.

## Show the auth UI

The simplest way to let users connect an external wallet is to show the Dynamic auth UI. The SDK presents available wallet options, opens the selected wallet app, and handles the redirect automatically.

```kotlin theme={"system"}
val sdk = DynamicSDK.getInstance()
sdk.ui.showAuth()
```

## Listen for connected wallets

After a wallet is connected, it appears in the user's wallet list. Use `userWalletsChanges` to react to new or updated wallets:

```kotlin theme={"system"}
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dynamic.sdk.android.DynamicSDK
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

class WalletViewModel : ViewModel() {
    private val sdk = DynamicSDK.getInstance()

    init {
        sdk.wallets.userWalletsChanges
            .onEach { wallets ->
                // Handle wallet list updates
            }
            .launchIn(viewModelScope)
    }
}
```

## Filter connected wallets

You can separate EVM and Solana wallets by chain:

```kotlin theme={"system"}
val evmWallets = sdk.wallets.userWallets.filter {
    it.chain.uppercase() == "EVM"
}

val solanaWallets = sdk.wallets.userWallets.filter {
    it.chain.uppercase() == "SOL"
}
```

## Set the primary wallet

If a user connects multiple wallets, you can set one as the primary wallet:

```kotlin theme={"system"}
fun setPrimaryWallet(wallet: BaseWallet) {
    viewModelScope.launch {
        val walletId = wallet.id ?: return@launch

        try {
            sdk.wallets.setPrimary(walletId)
        } catch (e: Exception) {
            println("Failed to set primary wallet: ${e.message}")
        }
    }
}
```

## Troubleshooting

* **Wallet app does not open**: Verify `redirectUrl` matches the scheme in `AndroidManifest.xml`, and that the deep link is whitelisted in the dashboard.
* **Wallet does not appear after connection**: Ensure `DynamicUI` is included in your Compose layout and you are collecting `userWalletsChanges`.
* **Connection fails after redirect**: Confirm `appOrigin` is set and matches the origin registered in the dashboard.

## Next steps

* [Wallet Creation](/docs/kotlin/wallet-creation) for embedded wallets
* [Wallet Management Reference](/docs/kotlin/sdk-reference/wallet-management)
* [Token Balances](/docs/kotlin/wallets/general/token-balances)
