Try the demo firstIt is recommended to check that the demo works with your passkey provider on the browsers and devices you plan to support. The Authenticator support page lists the combinations that have been tested.
Install
Requirements
- HTTPS, or
localhostin development. - A passkey provider that supports the WebAuthn PRF extension, such as iCloud Keychain, 1Password, or Google Password Manager. The Authenticator support page has the full list.
Create a passkey
createPasskeyWithPrfOutput prompts the user to create a passkey and returns 32 secret bytes.
credentialId. Returning visits use getPasskeyPrfOutput with that credential, which is covered in Signing in.
The credential metadata holds no key material, so localStorage is fine for it. Passing it back on the next sign-in lets the browser go straight to the same passkey rather than asking the user to pick one.
Derive a key
The 32 bytes returned by the passkey,prfOutput, can be used to derive a standard BIP-44 account. Deriving it this way keeps the account portable, so an exported mnemonic imports into MetaMask or Rabby and produces the same address.
index for additional accounts from the same passkey.
Send a transaction
A signing session holds the key, andtoViemAccount wraps it as a viem LocalAccount. It behaves like any other viem account and supports the same signing methods.
end() zeroes the key and cannot be undone, so the next transaction needs a new session. How long to keep one open is covered in Putting it together.
Use monad instead of monadTestnet for mainnet. Both ship in viem/chains.
Signing in
getPasskeyPrfOutput will prompt the authenticator in a discoverable mode, and the user should be able to choose a previously saved passkey.
Putting it together
There are two ways to arrange this, and the difference is how long the key stays in memory.Hold the session
Prompt the authenticator once, derive the key, and keep the session for as long as the user is signed in. This suits high-frequency workflows like trading, where a prompt per transaction is not workable. The key is in page memory for the whole session, and any script on the page can sign with it while it is live.disconnect() on sign-out, and consider calling it on an idle timeout as well.
Prompt per transaction
Run the ceremony for each transaction and end the session as soon as it is sent. The key exists only for the duration of the send, at the cost of a passkey prompt every time.using ends the session when the scope exits. If your build target does not support explicit resource management, call session.end() in a finally block instead.
Errors
mera throwsMeraError with a code. Use the code to identify the error, since message text can change between versions.
Notes
- A passkey is tied to the
rpIdit was created for. If the app moves to a new domain, the accounts can no longer be derived, and users would need the 24-word mnemonic to recover them. - Everything above derives the key from the passkey. When the key comes from somewhere else, such as a recovery phrase the user already has, secret vaults encrypt it once and decrypt it with the passkey.
createEd25519SigningSessionandgetSolanaAddressderive Solana accounts from the same passkey.

