> ## 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 iOS 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 Swift SDK initialized (see [Quickstart](/docs/swift/quickstart))
* `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:

```swift theme={"system"}
import DynamicSDKSwift

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

## 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.

Add your URL scheme to `Info.plist`:

```xml theme={"system"}
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleTypeRole</key>
    <string>Editor</string>
    <key>CFBundleURLName</key>
    <string>com.yourcompany.yourapp</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
  </dict>
</array>
```

## 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.

```swift theme={"system"}
import DynamicSDKSwift

let sdk = DynamicSDK.instance()
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:

```swift theme={"system"}
import DynamicSDKSwift
import Combine

@MainActor
class WalletViewModel: ObservableObject {
    @Published var wallets: [BaseWallet] = []

    private let sdk = DynamicSDK.instance()
    private var cancellables = Set<AnyCancellable>()

    func startListening() {
        sdk.wallets.userWalletsChanges
            .receive(on: DispatchQueue.main)
            .sink { [weak self] newWallets in
                self?.wallets = newWallets
            }
            .store(in: &cancellables)
    }
}
```

## Filter connected wallets

You can separate EVM and Solana wallets by chain:

```swift theme={"system"}
let evmWallets = sdk.wallets.userWallets.filter {
    $0.chain.uppercased() == "EVM"
}

let solanaWallets = sdk.wallets.userWallets.filter {
    $0.chain.uppercased() == "SOL"
}
```

## Set the primary wallet

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

```swift theme={"system"}
func setPrimaryWallet(_ wallet: BaseWallet) async {
    guard let walletId = wallet.id else { return }

    do {
        try await DynamicSDK.instance().wallets.setPrimary(walletId: walletId)
    } catch {
        print("Failed to set primary wallet: \(error)")
    }
}
```

## Troubleshooting

* **Wallet app does not open**: Verify `redirectUrl` matches the URL scheme in `Info.plist`, and that the deep link is whitelisted in the dashboard.
* **Wallet does not appear after connection**: Ensure you are listening to `userWalletsChanges`.
* **Connection fails after redirect**: Confirm `appOrigin` is set and matches the origin registered in the dashboard.

## Next steps

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