If the user loses their password, they will lose access to their wallet. There is no way to recover the password or the wallet without it.
Password encryption adds an extra layer of security to embedded wallets by requiring a password to decrypt the user’s key share. This ensures that even if an attacker gains access to the stored key share, they cannot use it without the password.
How it works
When password encryption is enabled:
- The user’s key share is encrypted with their password before storage
- Operations like signing transactions require the password to decrypt the share
- The password is never sent to Dynamic—decryption happens client-side
- No single party (Dynamic, encryption provider, or you) can access the wallet alone
Enabling password protection
You can enable password protection in the Dynamic Dashboard:
- Navigate to Embedded Wallets.
- Toggle Require Password to control whether users must set a password when creating a wallet.
Wallet creation flows
When password protection is enabled, you can choose between using Dynamic’s built-in UI or building your own.
Using Dynamic’s UI
If you have enabled Automatic Wallet Creation in the dashboard, Dynamic will automatically prompt the user to create a password when they log in. No additional code is required.
Using a custom UI
If you prefer to build your own password entry UI, you must manually create the wallet using createWalletAccount and pass the password.
import { useDynamicWaas } from "@dynamic-labs/sdk-react-core";
import { ChainEnum } from "@dynamic-labs/sdk-api-core";
const { createWalletAccount } = useDynamicWaas();
const createSecureWallet = async (password: string) => {
const wallet = await createWalletAccount(
[ChainEnum.Evm],
password
);
console.log('Password-protected wallet created:', wallet);
};
Password management
- Users set their own password during wallet creation
- They must enter the password to unlock the wallet
- Important: If the user forgets their password, wallet recovery may not be possible without a backup
Unlocking a wallet
Before performing operations with a password-protected wallet, unlock it using the useWalletPassword hook:
import { useWalletPassword } from "@dynamic-labs/sdk-react-core";
import { ChainEnum } from "@dynamic-labs/sdk-api-core";
const { unlockWallet, state } = useWalletPassword();
const handleUnlock = async (accountAddress: string, password: string) => {
const success = await unlockWallet({
accountAddress,
chainName: ChainEnum.Evm,
password,
});
if (success) {
console.log('Wallet unlocked for this session');
}
};
Once unlocked, the wallet remains unlocked for the rest of the user session (until logout). The user is only asked for the password once per session.
Unlocking one wallet unlocks all wallets associated with the user account. As a result, all wallets for a user must share the same password.
Updating the password
Change an existing password using updatePassword. This will update the password for all wallets associated with the user account.
import { useWalletPassword } from "@dynamic-labs/sdk-react-core";
import { ChainEnum } from "@dynamic-labs/sdk-api-core";
const { updatePassword } = useWalletPassword();
const changePassword = async (
accountAddress: string,
currentPassword: string,
newPassword: string
) => {
const success = await updatePassword({
accountAddress,
chainName: ChainEnum.Evm,
existingPassword: currentPassword,
newPassword,
});
if (success) {
console.log('Password updated');
}
};
Checking wallet lock state
Check if a wallet requires unlocking:
import { useWalletPassword } from "@dynamic-labs/sdk-react-core";
import { ChainEnum } from "@dynamic-labs/sdk-api-core";
const { checkWalletLockState } = useWalletPassword();
const checkState = async (accountAddress: string) => {
const recoveryState = await checkWalletLockState({
accountAddress,
chainName: ChainEnum.Evm,
});
console.log('Wallet recovery state:', recoveryState);
};
Complete example
import { useState } from 'react';
import { useDynamicWaas, useWalletPassword } from "@dynamic-labs/sdk-react-core";
import { ChainEnum } from "@dynamic-labs/sdk-api-core";
const PasswordProtectedWallet = () => {
const [password, setPassword] = useState('');
const { createWalletAccount, getWaasWallets } = useDynamicWaas();
const { unlockWallet, state } = useWalletPassword();
const createWallet = async () => {
const wallet = await createWalletAccount([ChainEnum.Evm], password);
console.log('Wallet created:', wallet);
};
const unlock = async () => {
const wallets = await getWaasWallets();
if (wallets.length > 0) {
await unlockWallet({
accountAddress: wallets[0].address,
chainName: ChainEnum.Evm,
password,
});
}
};
return (
<div>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter password"
/>
<button onClick={createWallet}>
Create Password-Protected Wallet
</button>
<button onClick={unlock} disabled={state.isLoading}>
Unlock Wallet
</button>
{state.error && <p>Error: {state.error}</p>}
</div>
);
};
Security considerations
Password-protected wallets are only as secure as the password itself. Enforce strong password requirements and educate users about password security.
- Password strength: Require minimum length and complexity
- No password recovery: If using user-provided passwords, there’s no way to recover a forgotten password without a backup
- Session-based unlock: Wallets remain unlocked for the session, reducing friction while maintaining security
- Combine with backups: Consider enabling Google Drive backup for additional recovery options