> ## 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 allow users to sign up and log in using their own wallet (MetaMask, Phantom, Coinbase Wallet, etc.).

> [!TIP]
>
> Building a React web app? The prebuilt [connect wallet widget](https://docs.dynamic.xyz/docs/javascript/building-ui/react-ui/connect-wallet-widget.md) renders the wallet list, chain choice, QR pairing, and error screens for you.

## Create and Initialize the Dynamic Client

First, install the client package and create a Dynamic Client with your environment ID.

```bash theme={"system"}
npm install @dynamic-labs-sdk/client
```

```javascript theme={"system"}
import { createDynamicClient } from '@dynamic-labs-sdk/client';

const dynamicClient = createDynamicClient({
  environmentId: 'YOUR_ENVIRONMENT_ID',
  metadata: {
    name: 'YOUR_APP_NAME',
    universalLink: 'YOUR_APP_URL',
    iconUrl: 'YOUR_APP_ICON_URL',
  },
});
```

See [Creating a Dynamic Client](https://docs.dynamic.xyz/docs/javascript/reference/client/create-dynamic-client.md) for more details.

## Add chain extensions for every chain you want to support

Install and add the extension for each chain you want in your adaptor. Each guide covers installation and how to add that chain's extension.

| Chain | Guide |
| - | - |
| EVM | [Adding EVM Extensions](https://docs.dynamic.xyz/docs/javascript/reference/evm/adding-evm-extensions.md) |
| Solana | [Adding Solana Extensions](https://docs.dynamic.xyz/docs/javascript/reference/solana/adding-solana-extensions.md) |
| MetaMask (EVM and Solana) | [MetaMask Connection Guide](https://docs.dynamic.xyz/docs/javascript/reference/wallets/metamask-connection-guide.md) |
| WalletConnect (EVM & Solana) | [WalletConnect Integration](https://docs.dynamic.xyz/docs/javascript/reference/wallets/walletconnect-integration.md) |
| Bitcoin | [Adding Bitcoin Extensions](https://docs.dynamic.xyz/docs/javascript/reference/bitcoin/adding-bitcoin-extension.md) |
| Tron | [Adding Tron Extensions](https://docs.dynamic.xyz/docs/javascript/reference/tron/adding-tron-extension.md) |
| Starknet | [Adding Starknet Extension](https://docs.dynamic.xyz/docs/javascript/reference/starknet/adding-starknet-extension.md) |
| Aptos | [Adding Aptos Extension](https://docs.dynamic.xyz/docs/javascript/reference/aptos/adding-aptos-extension.md) |
| Sui | [Adding Sui Extension](https://docs.dynamic.xyz/docs/javascript/reference/sui/adding-sui-extension.md) |

The list from `getAvailableWalletProvidersData()` (below) includes every wallet provider from every extension you added.

## Enable those chains in the Dynamic Console

In the [Dynamic Console](https://console.dynamic.xyz/dashboard/chains-and-networks), enable each chain you added an extension for (e.g. EVM, Solana, Bitcoin). Available options match the chain extensions above.

## Fetch available wallet providers (your adaptor's options)

Use `getAvailableWalletProvidersData` to get the full list of wallet providers your adaptor can offer. It includes every chain—wallet combination from the extensions you added (e.g. `metamaskevm`, `metamasksol`, `phantomevm`, `phantomsol`).

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { getAvailableWalletProvidersData } from '@dynamic-labs-sdk/client';
>
> const walletProvidersData = getAvailableWalletProvidersData();
>
> walletProvidersData.forEach((provider) => {
>   console.log(provider.key);                    // e.g., 'metamaskevm'
>   console.log(provider.metadata.displayName);   // e.g., 'MetaMask'
>   console.log(provider.groupKey);               // e.g., 'metamask' (for grouping)
>   console.log(provider.chain);                  // e.g., 'evm' or 'sol'
> });
> ```

> [tab] React
>
> Use `useGetAvailableWalletProvidersData` from `@dynamic-labs-sdk/react-hooks` — it re-renders whenever extensions load or change.
>
> ```tsx theme={"system"}
> import { useGetAvailableWalletProvidersData } from '@dynamic-labs-sdk/react-hooks';
> ```

See [Getting Available Wallets to Connect](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-available-wallets-to-connect.md) for more details.

> [!NOTE]
>
> Which wallets you can surface depends on the extensions you add to the client.
> Add `addMetaMaskEvmExtension` or `addMetaMaskSolanaExtension` for MetaMask SDK
> pairing (desktop QR and mobile), and `addWalletConnectEvmExtension` or
> `addWalletConnectSolanaExtension` for WalletConnect pairing with other mobile
> wallets. See [Adding extensions](https://docs.dynamic.xyz/docs/javascript/reference/adding-extensions.md).

## Display wallet options in your UI

Each wallet provider includes metadata (display name, icon). Use it to build your wallet selection UI (buttons, list, or modal).

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { getAvailableWalletProvidersData } from '@dynamic-labs-sdk/client';
>
> const walletProvidersData = getAvailableWalletProvidersData();
>
> // Example: render wallet buttons
> walletProvidersData.map((provider) => (
>   <button key={provider.key} onClick={() => handleConnect(provider.key)}>
>     <img src={provider.metadata.icon} alt={provider.metadata.displayName} />
>     {provider.metadata.displayName}
>   </button>
> ));
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useGetAvailableWalletProvidersData } from '@dynamic-labs-sdk/react-hooks';
>
> function WalletList() {
>   const { data: providers = [] } = useGetAvailableWalletProvidersData();
>
>   return (
>     <ul>
>       {providers.map((provider) => (
>         <li key={provider.key}>
>           <button onClick={() => handleConnect(provider)}>
>             <img src={provider.metadata.icon} alt={provider.metadata.displayName} />
>             {provider.metadata.displayName}
>           </button>
>         </li>
>       ))}
>     </ul>
>   );
> }
> ```

## Connect and verify

When the user picks a wallet from your adaptor UI, use the catalogue-key path for any wallet or one of the provider-key flows below for an installed wallet provider.

### Connect any wallet by catalogue key

Use `connectWalletOption` when you have a wallet options catalogue key, such as `'metamask'`, instead of a wallet provider key. It can connect wallets the user does not have installed by handing a URI pairing to `onConnectionUri`, or by opening the wallet's own in-app browser.

The function returns an unverified wallet account. Pair it with `verifyWalletAccount`, the verify flow below, to link the account to the user. See [Connect a wallet by catalogue key](https://docs.dynamic.xyz/docs/javascript/reference/wallets/connect-wallet-option.md) for the full reference.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { connectWalletOption, isMobile } from '@dynamic-labs-sdk/client';
>
> const walletAccount = await connectWalletOption({
>   onConnectionUri: ({ uri }) => {
>     if (isMobile()) {
>       window.location.href = uri;
>       return;
>     }
>
>     renderQrCode(uri);
>   },
>   walletKey: 'metamask',
> });
>
> console.log(`Connected: ${walletAccount.address}`);
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { isMobile } from '@dynamic-labs-sdk/client';
> import { useConnectWalletOption } from '@dynamic-labs-sdk/react-hooks';
>
> function ConnectWalletButton() {
>   const { mutate: connect, isPending } = useConnectWalletOption();
>
>   return (
>     <button
>       onClick={() =>
>         connect({
>           onConnectionUri: ({ uri }) => {
>             if (isMobile()) {
>               window.location.href = uri;
>               return;
>             }
>
>             renderQrCode(uri);
>           },
>           walletKey: 'metamask',
>         })
>       }
>       disabled={isPending}
>     >
>       {isPending ? 'Connecting...' : 'Connect wallet'}
>     </button>
>   );
> }
> ```

For installed wallet providers, the JS SDK supports three flows depending on when you want verification to occur.

### 1. Connect and verify in one step

The wallet account is only added after a successful verification signature. Use this for login/signup flows.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { connectAndVerifyWithWalletProvider } from '@dynamic-labs-sdk/client';
>
> const walletAccount = await connectAndVerifyWithWalletProvider({
>   walletProviderKey: 'metamaskevm',
> });
>
> // walletAccount is now verified and associated to a Dynamic user
> console.log(walletAccount.address);
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useConnectAndVerifyWithWalletProvider } from '@dynamic-labs-sdk/react-hooks';
>
> function ConnectWalletButton({ walletProviderKey }: { walletProviderKey: string }) {
>   // On success, `data` holds the verified walletAccount and `useGetWalletAccounts()` consumers re-render.
>   const { mutate: connectAndVerify, data, isPending } = useConnectAndVerifyWithWalletProvider();
>
>   return (
>     <>
>       <button onClick={() => connectAndVerify({ walletProviderKey })} disabled={isPending}>
>         {isPending ? 'Connecting…' : 'Connect wallet'}
>       </button>
>       {data && <p>Verified: {data.address}</p>}
>     </>
>   );
> }
> ```

### 2. Connect without verifying

The wallet account is added to the session but not yet associated to a Dynamic user. Use this to defer verification.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { connectWithWalletProvider } from '@dynamic-labs-sdk/client';
>
> const walletAccount = await connectWithWalletProvider({
>   walletProviderKey: 'metamaskevm',
> });
>
> // walletAccount is connected but not verified (session-only)
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useConnectWithWalletProvider } from '@dynamic-labs-sdk/react-hooks';
>
> function ConnectButton({ walletProviderKey }: { walletProviderKey: string }) {
>   const { mutate: connect, isPending } = useConnectWithWalletProvider();
>
>   // walletAccount (from data) is connected but not verified (session-only)
>   return (
>     <button onClick={() => connect({ walletProviderKey })} disabled={isPending}>
>       Connect
>     </button>
>   );
> }
> ```

### 3. Verify a previously connected account

Verify a wallet that was connected but not yet verified. This associates it with a Dynamic user.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { verifyWalletAccount } from '@dynamic-labs-sdk/client';
>
> const verifiedWalletAccount = await verifyWalletAccount({
>   walletAccount,
> });
>
> // walletAccount now has a verifiedCredentialId and is associated to a Dynamic user
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { type WalletAccount } from '@dynamic-labs-sdk/client';
> import { useVerifyWalletAccount } from '@dynamic-labs-sdk/react-hooks';
>
> function VerifyWalletButton({ walletAccount }: { walletAccount: WalletAccount }) {
>   const { mutate: verifyWalletAccount, isPending } = useVerifyWalletAccount();
>
>   return (
>     <button onClick={() => verifyWalletAccount({ walletAccount })} disabled={isPending}>
>       {isPending ? 'Verifying…' : 'Verify wallet'}
>     </button>
>   );
> }
> ```

See [Connecting and Verifying a Wallet](https://docs.dynamic.xyz/docs/javascript/reference/wallets/connect-and-verify-wallet.md) for more details.

## Get all connected wallet accounts

Retrieve every wallet account the user has connected (across all chains) using `getWalletAccounts`.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { getWalletAccounts } from '@dynamic-labs-sdk/client';
>
> const walletAccounts = getWalletAccounts();
>
> walletAccounts.forEach((account) => {
>   console.log(account.address);
>   console.log(account.verifiedCredentialId); // null if not verified
> });
> ```

> [tab] React
>
> Use `useGetWalletAccounts` from `@dynamic-labs-sdk/react-hooks` — it re-renders whenever accounts are added or removed.
>
> ```tsx theme={"system"}
> import { useGetWalletAccounts } from '@dynamic-labs-sdk/react-hooks';
>
> function WalletAccountsList() {
>   const { data: walletAccounts = [] } = useGetWalletAccounts();
>
>   return (
>     <ul>
>       {walletAccounts.map((account) => (
>         <li key={account.id}>{account.address}</li>
>       ))}
>     </ul>
>   );
> }
> ```

See [Getting Wallet Accounts](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-wallet-accounts.md) for more details.

## Related

* [Connect a wallet by catalogue key](https://docs.dynamic.xyz/docs/javascript/reference/wallets/connect-wallet-option.md)
* [Wallet Provider Events](https://docs.dynamic.xyz/docs/javascript/reference/wallets/wallet-provider-events.md)
* [Getting Native Balance](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-native-balance.md)
* [Signing Messages](https://docs.dynamic.xyz/docs/javascript/reference/wallets/sign-message.md)
* [Removing Wallet Accounts](https://docs.dynamic.xyz/docs/javascript/reference/wallets/remove-wallet-account.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.