Skip to main content
A passkey is a passwordless credential stored on the user’s device (or password manager). The user signs in with the same biometric or PIN they use to unlock their device — no password, nothing to remember.
Passkeys are a sign-in method, not a sign-up method. A user cannot create an account with a passkey. The order is always:
  1. The user signs up with another method (email/SMS OTP, social, wallet).
  2. While authenticated, they register a passkey.
  3. On a later visit, they sign in with that passkey.
registerPasskey requires an authenticated user; signInWithPasskey requires an already-registered passkey. Build your UI around that sequence.

Prerequisites

Before this: create and initialize a Dynamic client (see Creating a Dynamic Client, Initializing the Dynamic Client). Enable Passkey in your Dynamic dashboard. Passkeys use WebAuthn, which requires a secure context (HTTPS, or localhost in development).

Register a passkey

Call registerPasskey while the user is signed in — for example, in an “enable faster sign in” prompt right after sign-up, or from an account-security screen. It triggers the browser’s passkey-creation dialog, then stores the credential against the user.
Wire the call to your “enable faster sign in” button. Disable it while the browser dialog is open so the user can’t trigger two prompts at once.
import { registerPasskey } from '@dynamic-labs-sdk/client';

const button = document.querySelector<HTMLButtonElement>('#add-passkey')!;

button.addEventListener('click', async () => {
  button.disabled = true;
  try {
    // The browser prompts the user to create a passkey (Face ID, fingerprint, etc.)
    await registerPasskey();
    // showConfirmation is your implementation.
    showConfirmation('Passkey added.');
  } finally {
    button.disabled = false;
  }
});

Sign in with a passkey

For returning users who already registered a passkey, a single button is enough. signInWithPasskey opens the browser’s passkey picker and, on success, authenticates the user.
import { signInWithPasskey } from '@dynamic-labs-sdk/client';

const button = document.querySelector<HTMLButtonElement>('#passkey-sign-in')!;

button.addEventListener('click', async () => {
  // Opens the browser's passkey picker; resolves with the authenticated user.
  const { user } = await signInWithPasskey();
  // renderApp is your implementation.
  renderApp(user);
});
Offer “Sign in with a passkey” alongside your other sign-in options rather than as the only choice — a returning user might be on a device where they haven’t registered one yet.

List and remove passkeys

Let users see and manage their registered passkeys from an account-security screen. getPasskeys returns the user’s passkeys; deletePasskey removes one by id. Each passkey has an optional user-assigned alias, plus createdAt and the origin it was registered on.
Render the user’s passkeys into a list, each with a “Remove” button that calls deletePasskey and re-renders.
import { getPasskeys, deletePasskey } from '@dynamic-labs-sdk/client';

const list = document.querySelector<HTMLUListElement>('#passkey-list')!;

async function renderPasskeys() {
  const passkeys = await getPasskeys();
  list.replaceChildren();

  for (const passkey of passkeys) {
    const item = document.createElement('li');
    const added = new Date(passkey.createdAt).toLocaleDateString();
    item.textContent = `${passkey.alias ?? 'Passkey'} · added ${added} `;

    const remove = document.createElement('button');
    remove.textContent = 'Remove';
    remove.addEventListener('click', async () => {
      await deletePasskey({ passkeyId: passkey.id });
      renderPasskeys();
    });

    item.append(remove);
    list.append(item);
  }
}

renderPasskeys();
Removing a passkey is a sensitive action, so it may require the user to re-authenticate (step-up). See Step-up authentication for how to handle that prompt.

Handling errors

ErrorCauseResolution
NoWebAuthNSupportErrorThe browser or device doesn’t support WebAuthn.Hide the passkey option and fall back to another sign-in method.
NoPasskeyCredentialsFoundErrorSign-in was attempted but the user has no passkey for this app.Prompt them to sign in another way, then register a passkey.
Browser cancellationThe user dismissed the passkey dialog, or it timed out.The call rejects — leave the user on the current screen and let them retry.
import {
  signInWithPasskey,
  NoWebAuthNSupportError,
  NoPasskeyCredentialsFoundError,
} from '@dynamic-labs-sdk/client';

try {
  await signInWithPasskey();
} catch (error) {
  if (error instanceof NoWebAuthNSupportError) {
    // This device can't use passkeys — offer email or social sign-in instead.
  } else if (error instanceof NoPasskeyCredentialsFoundError) {
    // No passkey registered yet — send the user through another method first.
  } else {
    // User cancelled the prompt, or it timed out — let them try again.
  }
}

See also

Last modified on July 9, 2026