Skip to main content
mera derives EVM accounts from a passkey. Users create an account with Face ID, Touch ID, or a security key, and the same passkey reproduces the same accounts on every sign-in. The accounts are regular EOAs. There is nothing to deploy, and no bundler or MPC service to run. Once you have an address, the rest is ordinary viem against a Monad RPC.
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 localhost in 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.
Desktop ChromeOn desktop Chrome, only passkeys saved to Google Password Manager return PRF. When Chrome saves to the local profile instead, the passkey is created but mera throws PRF_UNAVAILABLE. This is the most common setup failure.

Create a passkey

createPasskeyWithPrfOutput prompts the user to create a passkey and returns 32 secret bytes.
Every call creates a new passkey, and each passkey produces a different set of accounts. Run this once during onboarding and store the returned 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.
Increment index for additional accounts from the same passkey.

Send a transaction

A signing session holds the key, and toViemAccount 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.
GasMonad charges the gasLimit you declare, not the gas used. Pass an explicit gas value, such as 21_000n for a native transfer, instead of letting an estimate stand. See Gas pricing.

Signing in

With a fresh device, 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.
Call 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 throws MeraError with a code. Use the code to identify the error, since message text can change between versions.

Notes

  • A passkey is tied to the rpId it 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.
  • createEd25519SigningSession and getSolanaAddress derive Solana accounts from the same passkey.

Further resources

You can check out the mera docs for more details. The project is open source, so you can also check out the code on GitHub.