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.