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.
Passkeys use cryptographic key pairs stored on the user’s device. Authentication happens with a biometric check (such as Face ID, Touch ID, or a fingerprint scan)
or a local device PIN. This makes passkeys both safer—since they can’t be phished or reused—and easier to use, since users don’t need to remember or type credentials.
Prerequisites
- You need to have the Dynamic Client initialized.
- You need to have the passkey MFA enabled in your environment’s settings in the Dynamic dashboard.
Registering a new passkey
Calling registerPasskey will prompt the user to register a new passkey in their device and register it in the Dynamic server,
so next time the user can complete an MFA challenge with it or even sign-in with it if enabled in the environment’s settings.
Registering a passkey will automatically authenticate it, so you don’t need to call authenticatePasskeyMFA after registering a passkey.
import { registerPasskey } from '@dynamic-labs-sdk/client';
const register = async () => {
await registerPasskey();
};
Doing MFA authentication with a passkey
Calling authenticatePasskeyMFA will prompt the user to authenticate with a passkey in their device and complete an MFA challenge.
The authentication will be successful if the user authenticates with the passkey in their device and it gets validated in the Dynamic server.
import { authenticatePasskeyMFA } from '@dynamic-labs-sdk/client';
const onLogin = async () => {
await authenticatePasskeyMFA();
};
With step-up authentication (recommended)
Pass requestedScopes to receive an elevated access token for sensitive actions:
import { authenticatePasskeyMFA } from '@dynamic-labs-sdk/client';
const onExportPrivateKeyClick = async () => {
await authenticatePasskeyMFA({
requestedScopes: ['wallet:export'],
});
// Elevated token is now stored — the SDK attaches it automatically
await exportWaasPrivateKey(params);
};
With MFA token (deprecated)
createMfaToken is deprecated and will be removed in the next major version. Use requestedScopes instead. See migration guide.
import { authenticatePasskeyMFA } from '@dynamic-labs-sdk/client';
const onExportPrivateKeyClick = async () => {
await authenticatePasskeyMFA({
createMfaToken: { singleUse: true },
});
await exportWaasPrivateKey(params);
};
Deleting a passkey
Calling deletePasskey will delete a passkey from the Dynamic server.
import { deletePasskey } from '@dynamic-labs-sdk/client';
const delete = async () => {
// Replace 'passkey-id' with the actual ID of the passkey you want to delete
await deletePasskey({passkeyId: 'passkey-id'});
};
Getting all registered passkeys for a user
Calling getPasskeys will return all registered passkeys for the authenticated user.
import { getPasskeys } from '@dynamic-labs-sdk/client';
const getUserPasskeys = async () => {
const passkeys = await getPasskeys();
console.log(passkeys);
};
React
Use useState to track passkey list and button handler for registration/deletion:
import { registerPasskey, getPasskeys, deletePasskey, authenticatePasskeyMFA } from '@dynamic-labs-sdk/client';
import { useEffect, useState } from 'react';
function PasskeyManager() {
const [passkeys, setPasskeys] = useState([]);
useEffect(() => {
getPasskeys().then(setPasskeys);
}, []);
const handleRegister = async () => {
await registerPasskey();
const updated = await getPasskeys();
setPasskeys(updated);
};
const handleDelete = async (passkeyId) => {
await deletePasskey({ passkeyId });
setPasskeys((prev) => prev.filter((p) => p.id !== passkeyId));
};
return (
<div>
<button onClick={handleRegister}>Register New Passkey</button>
<ul>
{passkeys.map((p) => (
<li key={p.id}>
{p.name ?? p.id}
<button onClick={() => handleDelete(p.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
function PasskeyMfaButton() {
const handleAuth = async () => {
await authenticatePasskeyMFA({ requestedScopes: ['wallet:export'] });
// Proceed with the sensitive action
};
return <button onClick={handleAuth}>Authenticate with Passkey</button>;
}