Skip to content

Passkey Authentication

Register and login with WebAuthn

Passkeys are the fastest passwordless option for most apps. Users authenticate with Face ID, Touch ID, a fingerprint, a device PIN, or a hardware security key.

Use passkeys when you want an email-free wallet flow. Passkeys use WebAuthn, and the browser handles the passkey prompt.

Configure Wagmi

Passkeys work with the same connector setup from the Quickstart:

import { zeroDevWallet } from '@zerodev/wallet-react'
import { createConfig, http } from 'wagmi'
import { arbitrumSepolia } from 'wagmi/chains'
 
const projectId = '<your-project-id>'
const chainRpcUrl = 'https://sepolia-rollup.arbitrum.io/rpc'
 
export const config = createConfig({
  chains: [arbitrumSepolia],
  connectors: [
    zeroDevWallet({
      projectId,
      chains: [arbitrumSepolia],
      mode: '7702',
    }),
  ],
  transports: {
    [arbitrumSepolia.id]: http(chainRpcUrl),
  },
})

Set a custom RP ID

The relying party ID, or RP ID, is the domain WebAuthn uses to scope a passkey. A passkey registered for one RP ID can only be used later with that same RP ID.

By default, the SDK uses the current hostname. Set rpId when you want passkeys to work across subdomains of the same site.

zeroDevWallet({
  projectId,
  chains: [arbitrumSepolia],
  rpId: 'example.com',
})

Use a domain only. Do not include a protocol, path, or port. For example, if your app runs on https://app.example.com and you want passkeys to work across your app's subdomains, use example.com.

Choose the RP ID before users register passkeys. You cannot transfer an existing passkey from one RP ID to another; changing the RP ID later usually means users must register new passkeys.

Learn more in the WebAuthn RP ID docs.

Add passkey login

Use useRegisterPasskey for new users and useLoginPasskey for returning users.

Registration creates a new passkey. Login asks the user to choose an existing passkey and approve the browser prompt. In Chrome, for example, that prompt may use the OS password manager, device biometrics, a PIN, or a hardware security key.

import { useLoginPasskey, useRegisterPasskey } from '@zerodev/wallet-react'
import { useAccount, useDisconnect } from 'wagmi'
 
export function PasskeyLogin() {
  const { address, isConnected } = useAccount()
  const { disconnect } = useDisconnect()
  const registerPasskey = useRegisterPasskey()
  const loginPasskey = useLoginPasskey()
 
  if (isConnected) {
    return (
      <div>
        <p>Connected: {address}</p>
        <button type="button" onClick={() => disconnect()}>
          Disconnect
        </button>
      </div>
    )
  }
 
  return (
    <div>
      <button
        type="button"
        disabled={registerPasskey.isPending}
        onClick={() => registerPasskey.mutate()}
      >
        {registerPasskey.isPending ? 'Registering...' : 'Register passkey'}
      </button>
 
      <button
        type="button"
        disabled={loginPasskey.isPending}
        onClick={() => loginPasskey.mutate()}
      >
        {loginPasskey.isPending ? 'Logging in...' : 'Login with passkey'}
      </button>
 
      {registerPasskey.error ? <p>{registerPasskey.error.message}</p> : null}
      {loginPasskey.error ? <p>{loginPasskey.error.message}</p> : null}
    </div>
  )
}

How it works

  1. useRegisterPasskey opens the browser's WebAuthn prompt and creates a wallet linked to the new passkey.
  2. useLoginPasskey opens the WebAuthn prompt and authenticates an existing passkey.
  3. After either flow succeeds, the SDK creates a session and connects the ZeroDev Wagmi connector.

Use useAccount, useSignMessage, and useSendTransaction after authentication.

Notes

  • Passkeys require a secure context. localhost works for local development; production apps should use HTTPS.
  • The dashboard ACL allowlist must include the exact origin you open in the browser.
  • Passkeys can sync across devices through platform password managers, depending on the user's device, browser, and account recovery settings.

Next steps