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

# Authenticate with External Wallets

External wallets let users sign up and log in to your app using wallets they already own, such as MetaMask or Phantom. On mobile, these connections happen via WalletConnect, which deep links to the user's wallet app for approval.

<Tip>
  External wallets and embedded wallets are completely compatible. A user can start with an embedded wallet and also link their branded wallet, or vice versa.
</Tip>

## Enable External Wallet Login

<Steps>
  <Step title="Enable Chains">
    Enable the chains you want to support in [the Chains section of the dashboard](https://app.dynamic.xyz/dashboard/chains-and-networks). We support Ethereum, all EVM-compatible networks, Solana, and more.
  </Step>

  <Step title="Enable Wallet Login">
    In [the Log in & User Profile section of the dashboard](https://app.dynamic.xyz/dashboard/log-in-user-profile), toggle on **Wallet Log in** under "External Wallets".
  </Step>

  <Step title="Set Up Deep Links">
    External wallet connections on mobile rely on deep links to redirect users between your app and their wallet app.

    <Warning>Make sure you've set up your deep link URLs correctly. See [Deeplink URLs](/react-native/reference/deeplink-urls).</Warning>
  </Step>
</Steps>

## Multi-Wallet

In the dashboard under External Wallets, you can toggle on **Multi-Wallet**. When enabled, users can connect more than one wallet to their account and switch between them without signing out. Learn more on [the Multi-Wallet page](/react-native/wallets/external-wallets/multi-wallet).

## How WalletConnect Works on Mobile

When a user connects an external wallet in React Native, the SDK uses WalletConnect under the hood. The flow is:

1. Your app presents a list of available wallets
2. The user taps a wallet (e.g. MetaMask)
3. The SDK generates a WalletConnect URI and deep links to the wallet app
4. The user approves the connection in their wallet app
5. The wallet app redirects back to your app with the connection established

This all happens automatically when you use `connectWallet` — you don't need to manage WalletConnect sessions directly.

## Using Our UI

Once enabled, external wallet login is available by default in the Dynamic UI. Simply show the auth flow and users will see available wallets:

```ts React Native theme={"system"}
import { dynamicClient } from '<path to client file>';

// Opens the Dynamic auth modal with wallet options
dynamicClient.ui.auth.show();
```

## Using Your UI

### Fetch Available Wallets

Access the list of available wallets through the `walletOptions` property. Each option includes metadata about the wallet, including whether it uses WalletConnect.

```tsx React Native theme={"system"}
import { useReactiveClient } from '@dynamic-labs/react-hooks';
import { dynamicClient } from '<path to client file>';

export const useDynamicClient = () => useReactiveClient(dynamicClient);

const WalletList = () => {
  const client = useDynamicClient();
  const walletOptions = client.wallets.walletOptions;

  // Each option contains:
  // - key: unique identifier (e.g. 'metamask', 'phantom')
  // - name: display name
  // - chain: blockchain (e.g. 'EVM', 'SOL')
  // - isWalletConnect: whether it connects via WalletConnect
  // - metadata: { id, name, icon, brandColor, deepLinks }

  return (
    <View>
      {walletOptions
        .filter((option) => option.chain !== null)
        .map((option) => (
          <Text key={`${option.key}-${option.chain}`}>
            {option.name} ({option.chain})
          </Text>
        ))}
    </View>
  );
};
```

### Connect to a Wallet

Use `connectWallet` with the wallet's `key` to initiate the connection. On mobile, this automatically handles the WalletConnect deep link flow — opening the wallet app for approval and returning the connected wallet when done.

```tsx React Native theme={"system"}
import { useReactiveClient } from '@dynamic-labs/react-hooks';
import { dynamicClient } from '<path to client file>';
import { View, TouchableOpacity, Text, Image, Alert } from 'react-native';

export const useDynamicClient = () => useReactiveClient(dynamicClient);

const WalletSelector = () => {
  const client = useDynamicClient();
  const walletOptions = client.wallets.walletOptions.filter(
    (option) => option.chain !== null
  );

  const handleConnect = async (walletKey: string) => {
    try {
      const wallet = await client.wallets.connectWallet(walletKey);
      console.log('Connected:', wallet.address);
    } catch (error) {
      console.error('Connection failed:', error);
    }
  };

  return (
    <View>
      {walletOptions.map((option) => (
        <TouchableOpacity
          key={`${option.key}-${option.chain}`}
          onPress={() => handleConnect(option.key)}
        >
          {option.metadata.icon && (
            <Image
              source={{ uri: option.metadata.icon }}
              style={{ width: 32, height: 32 }}
            />
          )}
          <Text>{option.name}</Text>
        </TouchableOpacity>
      ))}
    </View>
  );
};
```

### Filter WalletConnect Wallets

You can filter wallets to show only WalletConnect-compatible options, or separate them into categories:

```tsx React Native theme={"system"}
const client = useDynamicClient();
const walletOptions = client.wallets.walletOptions;

// Only WalletConnect wallets
const wcWallets = walletOptions.filter((w) => w.isWalletConnect);

// Only EVM wallets
const evmWallets = walletOptions.filter((w) => w.chain === 'EVM');

// Only Solana wallets
const solWallets = walletOptions.filter((w) => w.chain === 'SOL');

// Multichain wallets (appear in multiple chains)
const multichainKeys = walletOptions
  .filter((w) => w.group !== null)
  .map((w) => w.key);
```

You can also filter wallets at the client level using `walletsFilter` in your client configuration:

```tsx React Native theme={"system"}
import { createClient } from '@dynamic-labs/client';
import { ReactNativeExtension } from '@dynamic-labs/react-native-extension';

const client = createClient({
  environmentId: 'your-environment-id',
  appOrigin: 'https://your-app.com',
  walletsFilter: (wallets) =>
    wallets.filter((w) => ['metamask', 'phantom', 'rainbow'].includes(w.key)),
})
  .extend(ReactNativeExtension({ appOrigin: 'https://your-app.com' }));
```

### Access Connected Wallets

Once a wallet is connected, access it through `userWallets` and `primary`:

```tsx React Native theme={"system"}
const client = useDynamicClient();

// All connected wallets
const wallets = client.wallets.userWallets;

// Primary wallet
const primaryWallet = client.wallets.primary;

// Set a different wallet as primary
await client.wallets.setPrimary({ walletId: wallet.id });
```

### Wallet Operations

After connecting, you can perform operations on any connected wallet:

```tsx React Native theme={"system"}
const client = useDynamicClient();
const wallet = client.wallets.primary;

// Sign a message
const { signedMessage } = await client.wallets.signMessage({
  wallet,
  message: 'Hello from Dynamic!',
});

// Get balance
const { balance } = await client.wallets.getBalance({ wallet });

// Get current network
const { network } = await client.wallets.getNetwork({ wallet });

// Switch network (EVM)
await client.wallets.switchNetwork({
  wallet,
  chainId: 137, // Polygon
});

// Send balance
const { hash } = await client.wallets.sendBalance({
  wallet,
  amount: '0.01',
  toAddress: '0x...',
});
```

### Listen for Wallet Events

React to wallet state changes using event listeners:

```tsx React Native theme={"system"}
const client = useDynamicClient();

// When a new wallet is connected
client.wallets.on('walletAdded', ({ wallet, userWallets }) => {
  console.log('New wallet connected:', wallet.address);
});

// When a wallet is disconnected
client.wallets.on('walletRemoved', ({ wallet }) => {
  console.log('Wallet disconnected:', wallet.address);
});

// When the primary wallet changes
client.wallets.on('primaryChanged', (primary) => {
  console.log('Primary wallet:', primary?.address);
});

// When a message is signed
client.wallets.on('messageSigned', ({ messageToSign, signedMessage }) => {
  console.log('Signed:', signedMessage);
});
```

## Connected vs Authenticated

By default, external wallets use "connect-and-sign" mode, where users both connect their wallet and sign a message to prove ownership. You can also use "connect-only" mode where users just connect without signing.

Read about the implications of each mode in [Connected vs Authenticated](/react-native/wallets/external-wallets/connected-vs-authenticated) to decide what's right for your use case.

## Further Reading

<CardGroup cols={2}>
  <Card title="Multi-Wallet" href="/react-native/wallets/external-wallets/multi-wallet">
    Allow users to connect multiple wallets to their account.
  </Card>

  <Card title="Link/Unlink Wallets" href="/react-native/wallets/using-wallets/general/link-a-wallet">
    Link additional wallets after authentication.
  </Card>

  <Card title="Wallet Events" href="/react-native/wallets/using-wallets/general/wallet-events">
    Listen to wallet state changes and events.
  </Card>

  <Card title="External Wallets Overview" href="/react-native/wallets/external-wallets/external-wallets-overview">
    Deep dive into external wallet configuration.
  </Card>
</CardGroup>
