Skip to main content
Mera v0.2.0 adds React Native support through a native WebAuthn client. A user can create a passkey on the web, sign in with the synced passkey on iOS or Android, and derive the same Monad account in each app. The web app and mobile app must use the same relying party ID (rpId). The passkey provider must also sync the passkey to the mobile device and support the WebAuthn PRF extension.
The React Native demo shows the complete flow, including passkey sign-in, biometric-gated device storage, account recovery, and transaction signing.

Requirements

  • Node.js 24 or later
  • An initialized Expo project with expo installed
  • @category-labs/mera v0.2.0 or later
  • An HTTPS host that you control for the relying party ID and platform association files
  • iOS 18 or later, or Android 9 or later with a passkey provider that supports PRF
  • Xcode for iOS, or Android Studio and a JDK with keytool on your PATH for Android
The Expo examples below use a development build because react-native-passkey calls native platform APIs.

Install

Run the following commands from the root of an existing Expo project. To create a new project instead:
The project creation command installs expo and creates the app entry point used in this guide. You do not need to clone the Mera demo. Install Mera, the react-native-passkey client, and the other dependencies:

Add the Hermes crypto polyfill

Mera needs crypto.getRandomValues, which Hermes does not provide. Create a polyfill using expo-crypto:
src/polyfills.ts
Import the polyfill from the app entry point before importing code that uses Mera:
index.ts
Choose a host such as accounts.example.com for the relying party ID. Use only the host name, without https:// or a path. To reuse a passkey created by a web app, the web app must create it with this same rpId. Each mobile platform also requires a public association file that authorizes the native app to use credentials for the host.

iOS

Serve the following JSON from https://accounts.example.com/.well-known/apple-app-site-association:
Replace TEAM_ID with your Apple team ID and com.example.app with the app’s bundle identifier. Add the associated domain to the Expo configuration:
app.config.ts

Android

Serve the following JSON from https://accounts.example.com/.well-known/assetlinks.json:
Replace the package name and fingerprint with those of the Android app. Include the fingerprint for every certificate used to sign the app. The next section shows how to print the fingerprint for the default Expo debug certificate.

Build the native app

Generate the ios/ and android/ projects after configuring the app. Expo Prebuild creates these directories and links react-native-passkey with the native projects:
For an Android development build, print the fingerprint of the generated debug certificate and replace SHA256_FINGERPRINT in assetlinks.json with the result:
Update and deploy assetlinks.json with this fingerprint before testing passkeys. Both platform association files must be publicly available over HTTPS, return JSON, and respond without a redirect. Then compile and run the development build. For iOS:
For Android:
Expo Go cannot run this app because it does not include the native passkey module.

Create or reuse a passkey

React Native does not expose the browser WebAuthn APIs. Pass Mera’s reactNativeWebAuthnClient to every function that runs a passkey ceremony:
src/passkey.ts
Calling signIn without a credential ID lets the platform offer any passkey available for the relying party. If the passkey created on the web has synced to the device, selecting it returns the same PRF output and therefore derives the same account.

Derive a Monad account

Derive the standard EVM BIP-44 key from the returned PRF output:
src/wallet.ts
The derivation path must match the web app. Increment index only when you intend to use another account from the same passkey.

Send a transaction

Create a signing session, adapt it to a viem account, and send a transaction on Monad:
src/send-transaction.ts
Use monad instead of monadTestnet for mainnet. See Gas pricing before using other transaction types.

Store and unlock the account

The credential ID is metadata and does not contain key material. The PRF output, however, can derive the account’s private keys and must be treated as secret key material. For a smoother mobile experience, an app can store the PRF output in platform secure storage protected by biometrics or the device credential. This lets the app unlock an existing account without showing the passkey picker for every transaction.
  • Do not store the PRF output in AsyncStorage or application logs.
  • End the signing session when the user locks the wallet, signs out, or the app’s session expires.
  • Clear temporary PRF, seed, and private-key buffers after deriving the session.
  • Request the passkey again before displaying a recovery phrase or performing another sensitive export.
The mobile demo storage implementation shows this pattern with Expo SecureStore.

Troubleshooting

  • PRF_UNAVAILABLE: The selected passkey provider or operating system did not return the PRF extension. Check Mera’s authenticator support.
  • PASSKEY_OPERATION_FAILED on the first request: Confirm that the association file is reachable without a redirect and contains the installed app’s exact bundle or package identifier and signing certificate.
  • The mobile address differs from the web address: Confirm that both apps use the same rpId, the same passkey, and the same BIP-44 account index.

Further resources