Passkey setup

Passkeys bind to a relying-party domain (rpId) that must vouch for your app. Without the association in place, createNativePasskeyCeremony({ rpId }) fails the ceremony with “RP ID cannot be validated”.

What is an rpId?

The rpId is the relying-party identifier: a domain you control, for example wallet.example.com. Passkeys created with a given rpId are bound to it, so the association files described in this guide must be served from exactly that domain over HTTPS. Using the same rpId across your web app and your mobile app means the same passkey, and therefore the same wallet, works on both.

Android

Serve https://<rpId>/.well-known/assetlinks.json listing your app’s package name and signing-certificate SHA-256 fingerprint with both relations the platform checks: delegate_permission/common.handle_all_urls and delegate_permission/common.get_login_creds.

Declare the association app-side too: an asset_statements string resource that references that assetlinks URL, wired up through a manifest meta-data entry. The demo’s Expo config plugin, apps/rn-wallet-demo/plugins/withAssetStatements.js, is a working example of both pieces for an Expo app.

At runtime the device needs Android 9+ (API 28), Google Play services with a signed-in Google account, and a device screen lock.

iOS (experimental)

Add the Associated Domains capability (webcredentials:<rpId>) to your app and serve https://<rpId>/.well-known/apple-app-site-association listing your Team ID and bundle id. Requires iOS 18 or newer at runtime.

Verify it works

supportsPasskeyPrf() surfaces as the supported flag returned by useWalletPasskey, reporting whether the platform prerequisites above are present. A supported device can still decline the ceremony, which surfaces as a normal error rather than an unsupported state.

See Use a passkey for the wiring pattern once the association is live.