Step-by-Step Guide

This guide shows you how to use Dynamic for authentication and as a signer for Crossmint Smart Wallets.

1

Create a Crossmint API Key

The first step is to obtain a client-side API key from Crossmint.

  1. Navigate to the “Integrate” section on the left navigation bar of the Crossmint console, and ensure you’re on the “API Keys” tab.
  2. Within the Client-side keys section, click the “Create new key” button in the top right.
  3. On the authorized origins section, enter http://localhost:3000 and click “Add origin”.
  4. Next, check the scopes labeled wallets.create, wallets.read, users.create.
  5. Check the “JWT Auth” box.
  6. Finally, create your key and save it for subsequent steps.
2

Configure Dynamic Authentication for your API Key

After the key is generated, you need to set it to require Dynamic auth tokens for authorization.

  1. Go to the Dynamic dashboard at https://app.dynamic.xyz/
  2. Select an existing project or create a new one

You need to make sure you’re using live keys for mainnets and sandbox keys for staging/testnets.

Dynamic Dashboard
  1. Expand the “Developers” section in the left-hand navigation and select “SDK and API Keys” to find your Dynamic Environment ID.
Dynamic Dashboard
  1. Copy the Dynamic Environment ID and return to the Crossmint developer console
  2. Within the JWT authentication section, select “3P Auth providers” option, and then select Dynamic
  3. Add your Environment ID and save changes
Dynamic Dashboard
3

Configure Chain Support in Dynamic

To integrate Crossmint Smart Wallets with Dynamic as the auth provider, you need to configure the chain you want to use:

  1. With the same project selected, select the “Chains and Networks” option in the left-hand navigation
  2. Click the EVM option to reveal a drawer where you can toggle chain support on and off
Dynamic Dashboard
  1. Enable the desired chain for smart wallet support (in this example, we’ll use polygon-amoy)
Dynamic Dashboard
4

Install Required Dependencies

Install the Crossmint React UI SDK and dynamic packages:

npm install @crossmint/client-sdk-react-ui @dynamic-labs/sdk-react-core @dynamic-labs/ethereum

Then, set up shadcn UI components:

npx shadcn-ui@latest init -d

Install the button and card components:

npx shadcn-ui@latest add button card
5

Configure Environment Variables

Add your Crossmint client-side API key and Dynamic Environment ID to your environment file:

NEXT_PUBLIC_DYNAMIC_ENV_ID=_YOUR_DYNAMIC_ENV_ID_
NEXT_PUBLIC_CROSSMINT_DYNAMIC_API_KEY=_YOUR_CROSSMINT_API_KEY_
6

Create the Provider Components

First, create a CrossmintDynamicProvider component that will wrap your application:

components/providers/CrossmintDynamicProvider.tsx
'use client';

import {
  CrossmintProvider,
  CrossmintWalletProvider,
} from '@crossmint/client-sdk-react-ui';
import { DynamicContextProvider } from '@dynamic-labs/sdk-react-core';
import { EthereumWalletConnectors } from '@dynamic-labs/ethereum';

const dynamicEnvId = process.env.NEXT_PUBLIC_DYNAMIC_ENV_ID ?? '';
const crossmintApiKey = process.env.NEXT_PUBLIC_CROSSMINT_DYNAMIC_API_KEY ?? '';

if (!dynamicEnvId || !crossmintApiKey) {
  throw new Error(
    'NEXT_PUBLIC_DYNAMIC_ENV_ID or NEXT_PUBLIC_CROSSMINT_DYNAMIC_API_KEY is not set'
  );
}

export default function CrossmintDynamicProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <DynamicContextProvider
      settings={{
        environmentId: dynamicEnvId,
        walletConnectors: [EthereumWalletConnectors],
      }}>
      <CrossmintProvider apiKey={crossmintApiKey}>
        <CrossmintWalletProvider defaultChain="polygon-amoy">
          {children}
        </CrossmintWalletProvider>
      </CrossmintProvider>
    </DynamicContextProvider>
  );
}

Now create a custom hook that connects Dynamic with Crossmint:

hooks/useDynamicConnector.tsx
'use client';

import {
  useCrossmint,
  useWallet as useCrossmintSmartWallet,
} from '@crossmint/client-sdk-react-ui';
import { isEthereumWallet } from '@dynamic-labs/ethereum';
import {
  getAuthToken,
  useDynamicContext,
  useIsLoggedIn,
} from '@dynamic-labs/sdk-react-core';
import { useEffect, useState } from 'react';

export function useDynamicConnector() {
  const { setJwt } = useCrossmint();
  const { primaryWallet: dynamicPrimaryWallet, sdkHasLoaded } =
    useDynamicContext();
  const isDynamicUserLoggedIn = useIsLoggedIn();
  const {
    getOrCreateWallet: getOrCreateCrossmintSmartWallet,
    status: crossmintSmartWalletStatus,
    error: crossmintSmartWalletError,
    wallet: crossmintWallet,
  } = useCrossmintSmartWallet();

  // State to track loading status
  const [isLoading, setIsLoading] = useState(true);

  // Step 1: Sync Dynamic JWT with Crossmint
  useEffect(() => {
    const syncDynamicJwt = async () => {
      try {
        const dynamicJwt = getAuthToken();
        setJwt(dynamicJwt ?? undefined);
      } catch (error) {
        setJwt(undefined);
        console.error('Failed to get Dynamic JWT:', error);
      }
    };

    if (isDynamicUserLoggedIn) {
      syncDynamicJwt();
    }
  }, [isDynamicUserLoggedIn, setJwt]);

  // Step 2: Get Dynamic wallet and create Crossmint wallet
  useEffect(() => {
    const createWalletWithDynamicSigner = async () => {
      setIsLoading(true);

      if (!dynamicPrimaryWallet || !isDynamicUserLoggedIn || !sdkHasLoaded) {
        setIsLoading(false);
        return;
      }

      try {

        if (!isEthereumWallet(dynamicPrimaryWallet)) {
          setIsLoading(false);
          return;
        }

        // Get the wallet client from Dynamic
        const dynamicWalletClient = await dynamicPrimaryWallet.getWalletClient();

        // Create a Crossmint Smart Wallet using the Dynamic wallet as signer
        await getOrCreateCrossmintSmartWallet({
          type: 'evm-smart-wallet',
          signer: dynamicWalletClient,
        });
      } catch (error) {
        console.error('Failed to create Crossmint wallet:', error);
      } finally {
        setIsLoading(false);
      }
    };

    createWalletWithDynamicSigner();
  }, [dynamicPrimaryWallet, isDynamicUserLoggedIn, sdkHasLoaded, getOrCreateCrossmintSmartWallet]);

  return {
    dynamicWallet: dynamicPrimaryWallet,
    crossmintWallet,
    crossmintSmartWalletStatus,
    crossmintSmartWalletError,
    isLoading: isLoading || crossmintSmartWalletStatus === 'in-progress' || !sdkHasLoaded,
  };
}
7

Update Your Layout

Update your app’s layout to use the CrossmintDynamicProvider:

app/layout.tsx
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
import CrossmintDynamicProvider from '@/components/providers/CrossmintDynamicProvider';

const inter = Inter({ subsets: ['latin'] });

export const metadata: Metadata = {
  title: 'Crossmint + Dynamic Integration',
  description: 'Example of using Crossmint with Dynamic Auth',
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <CrossmintDynamicProvider>
          <main className="flex min-h-screen flex-col items-center justify-between p-24">
            {children}
          </main>
        </CrossmintDynamicProvider>
      </body>
    </html>
  );
}
8

Create UI Components

Create a component that uses the Dynamic connector and displays wallet information:

components/WalletCard.tsx
'use client';

import { DynamicWidget } from '@dynamic-labs/sdk-react-core';
import { Card, CardContent } from '@/components/ui/card';
import { useDynamicConnector } from '@/hooks/useDynamicConnector';

export function WalletCard() {
  const {
    dynamicWallet,
    crossmintWallet,
    crossmintSmartWalletStatus,
    crossmintSmartWalletError,
    isLoading,
  } = useDynamicConnector();

  return (
    <Card className="w-full max-w-lg">
      <CardContent className="space-y-4 pt-6">
        <DynamicWidget />

        <div className="space-y-2 pt-4">
          <div className="text-sm text-muted-foreground">
            <strong>Crossmint Smart Wallet:</strong>{' '}
            {crossmintWallet?.address || 'Not connected'}
          </div>
          <div className="text-sm text-muted-foreground">
            <strong>Dynamic Signer Wallet:</strong>{' '}
            {dynamicWallet?.address || 'Not connected'}
          </div>
          <div className="text-sm text-muted-foreground">
            <strong>Status:</strong>{' '}
            {isLoading ? 'Loading...' : crossmintSmartWalletStatus}
          </div>

          {crossmintSmartWalletError && (
            <div className="text-sm text-red-500">
              <strong>Error:</strong> {crossmintSmartWalletError?.message}
            </div>
          )}
        </div>
      </CardContent>
    </Card>
  );
}
9

Create Your Main Page

Create your main page that uses the WalletCard component:

app/page.tsx
import { WalletCard } from '@/components/WalletCard';

export default function Home() {
  return (
    <div className="flex flex-col items-center gap-8">
      <h1 className="text-3xl font-bold">Crossmint + Dynamic Integration</h1>
      <p className="text-center max-w-2xl text-muted-foreground">
        This example demonstrates how to use Dynamic's wallet as a signer for Crossmint Smart Wallets.
        When you connect with Dynamic, your wallet serves as the signer for your Crossmint Smart Wallet.
      </p>
      <WalletCard />
    </div>
  );
}
10

Launch and Test

  1. Start your development server:
npm run dev
  1. Visit http://localhost:3000 in your browser
  2. Click the Dynamic widget to start the authentication flow
  3. Follow the prompts to authenticate using Dynamic
  4. Once logged in, you should see both your Dynamic wallet address and your Crossmint Smart Wallet address

How It Works

The integration between Dynamic and Crossmint involves these key components:

  1. Authentication Flow:
    • User connects wallet using Dynamic’s authentication
    • Dynamic provides the wallet and authentication token (JWT)
    • The Crossmint SDK uses the JWT from Dynamic to authenticate with Crossmint
  2. Wallet Creation:
    • The useDynamicConnector hook retrieves the primary wallet from Dynamic
    • It gets the wallet client from the Dynamic wallet to use as a signer
    • It creates a Crossmint Smart Wallet using the Dynamic wallet as the signer
  3. Key Benefits:
    • Users leverage their existing Dynamic authentication
    • No new key management required
    • The Dynamic wallet serves as a signer for the Crossmint Smart Wallet
    • Cross-chain support through Crossmint’s infrastructure