Passkey Authentication
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 aaHost = 'https://rpc.zerodev.app'
const chainRpcUrl = 'https://sepolia-rollup.arbitrum.io/rpc'
export const config = createConfig({
chains: [arbitrumSepolia],
connectors: [
zeroDevWallet({
projectId,
aaHost,
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,
aaHost,
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
useRegisterPasskeyopens the browser's WebAuthn prompt and creates a wallet linked to the new passkey.useLoginPasskeyopens the WebAuthn prompt and authenticates an existing passkey.- 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.
localhostworks 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.
- For full hook options and return values, see
useRegisterPasskeyanduseLoginPasskey.
Next steps
- Send a transaction
- Sign a message
- Integrate other login methods: Email OTP, Magic Link, or Google OAuth