Summary

This guide will show you how to create a secured embedded wallet with a passkey, completely headlessly. We will use the createPasskey and createEmbeddedWallet methods, available from the useEmbeddedWallet hook. Here are the steps we need to follow:

  1. Ensure the user is logged in
  2. Create a passkey for the user
  3. Create the embedded wallet with the passkey provided from the previous step

Pre-requisites

  • You have already set up the Dynamic SDK and wrapped your app with the DynamicContextProvider.
  • You have enabled Dynamic-powered embedded wallets and toggled “Manual Mode” on in the configuration.
  • You do not have the DynamicWidget component in your application code.

Step by step

Ensure the user is logged in

You can do this by implementing signup/login i.e. via email, or via SMS.

Create a passkey for the user

To create a passkey for the user, we will use the createPasskey method from the useEmbeddedWallet hook. This method will request the user create a passkey through their device UI and return a WebAuthnAttestation object to be used next while creating the embedded wallet.

Method signature:

createPasskey(): Promise<WebAuthnAttestation>

Implementation:

const { createPasskey } = useEmbeddedWallet();

const createPasskeyHandler = async () => {
  const webAuthnAttestation = await createPasskey({});
  console.log(webAuthnAttestation);
};

Create the embedded wallet

To create the embedded wallet, we will use the createEmbeddedWallet method from the useEmbeddedWallet hook. This method will create the wallet with the passkey we generated in the previous step.

Method signature:

createEmbeddedWallet(chains?: ChainEnum[], options?: { webAuthnAttestation: WebAuthnAttestation }): Promise<Wallet | undefined>

Implementation:

const { createEmbeddedWallet } = useEmbeddedWallet();

const createWalletHandler = async () => {
  const wallet = await createEmbeddedWallet(['EVM'], { webAuthnAttestation });
  console.log(wallet);
};

Full code example

export const CreateEmbeddedWalletWithPasskey: FC = () => {
  const { createEmbeddedWallet, createPasskey } = useEmbeddedWallet();
  const [result, setResult] = useState<string | undefined>(undefined);

  const onSubmitHandler = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    event.stopPropagation();

    const webAuthnAttestation = await createPasskey({});

    createEmbeddedWallet([ChainEnum.EVM, ChainEnum.Sol], { webAuthnAttestation })
      .then((result) => setResult(JSON.stringify(result, null, 2)))
      .catch((error) => setResult(JSON.stringify(error, null, 2)));
  };

  return (
    <form onSubmit={onSubmitHandler} className='create-session-method'>
      <p>Click to start the wallet creation flow</p>

      <button type='submit'>Create Wallet with passkey</button>

      {result}
    </form>
  );
};