Skip to content
Get startedGetting started →

Use mera with React Native

  • An HTTPS host for the relying party ID.
  • crypto.getRandomValues. Hermes does not provide it, so Hermes apps need a polyfill.
Terminal window
npm install @category-labs/mera react-native-passkey

This Expo example uses expo-crypto:

Terminal window
npx expo install expo-crypto
import {
function getRandomValues<T extends IntBasedTypedArray | UintBasedTypedArray>(typedArray: T): T

The getRandomValues() method of Crypto fills a provided TypedArray with cryptographically secure random values.

@paramtypedArray An integer based TypedArray to fill with cryptographically secure random values. It modifies the input array in place.

@returnThe input array filled with cryptographically secure random values.

@example

const byteArray = new Uint8Array(16);
Crypto.getRandomValues(byteArray);
console.log('Your lucky bytes: ' + byteArray);

getRandomValues
} from "expo-crypto";
if (typeof
module globalThis
globalThis
.
var crypto: Crypto
crypto
?.
Crypto.getRandomValues<T extends ArrayBufferView>(array: T): T

The Crypto.getRandomValues() method lets you get cryptographically strong random values.

MDN Reference

getRandomValues
!== "function") {
var Object: ObjectConstructor

Provides functionality common to all JavaScript objects.

Object
.
ObjectConstructor.defineProperty<typeof globalThis>(o: typeof globalThis, p: PropertyKey, attributes: PropertyDescriptor & ThisType<any>): typeof globalThis

Adds a property to an object, or modifies attributes of an existing property.

@paramo Object on which to add or modify the property. This can be a native JavaScript object (that is, a user-defined object or a built in object) or a DOM object.

@paramp The property name.

@paramattributes Descriptor for the property. It can be for a data property or an accessor property.

defineProperty
(
module globalThis
globalThis
, "crypto", {
PropertyDescriptor.configurable?: boolean | undefined
configurable
: true,
PropertyDescriptor.value?: any
value
: { ...
module globalThis
globalThis
.
var crypto: Crypto
crypto
,
getRandomValues: <T extends IntBasedTypedArray | UintBasedTypedArray>(typedArray: T) => T
getRandomValues
},
});
}

Load the polyfill before any code that imports mera:

import "./src/polyfills";

The relying party ID is the host the passkeys belong to. Use a host name without https:// or a path. The host must list the app in the platform file below.

Serve this JSON from https://account.example.com/.well-known/apple-app-site-association:

{
"webcredentials": {
"apps": ["TEAM_ID.com.example.app"]
}
}

Replace TEAM_ID with the Apple team ID and com.example.app with the bundle ID. Add this value under Associated Domains in Xcode:

webcredentials:account.example.com

Serve this JSON from https://account.example.com/.well-known/assetlinks.json:

[
{
"relation": ["delegate_permission/common.get_login_creds"],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": ["SHA256_FINGERPRINT"]
}
}
]

Replace the package name and fingerprint with those of the Android app. Include every certificate used to sign the app. For a local build, print the debug certificate with:

Terminal window
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android

Both files must be public over HTTPS and return JSON without a redirect.

reactNativeWebAuthnClient uses the iOS and Android API bindings from react-native-passkey. Pass it to each mera function that uses a passkey:

import {
function createPasskeyWithPrfOutput({ rp, user, timeout, prfSalt, webAuthnClient, }: createPasskeyWithPrfOutput.Options): Promise<createPasskeyWithPrfOutput.Result>

Creates a discoverable, user-verified passkey that requires WebAuthn PRF support and returns the first PRF output.

@paramoptions - Passkey creation inputs.

@returnsCredential metadata and the first PRF output.

@remarks

Runs one creation ceremony and shows one user-verification prompt. On authenticators that do not evaluate PRF during creation, a fallback assertion evaluates the same salt and shows a second prompt.

WebAuthn challenges and the credential's user handle (user.id) are generated internally, 32 random bytes each. An authenticator overwrites a discoverable credential that has the same rp.id and user.id, so a fresh handle per call adds a passkey instead of replacing one.

The credential is requested with fixed parameters: ES256 or RS256 key types, attestation "none", a required resident key, and required user verification (getPasskeyPrfOutput explains the requirement).

Any failure after the creation ceremony completes leaves the passkey on the authenticator, but the thrown error does not carry its metadata.

@throwsMeraError with code PRF_UNAVAILABLE when the authenticator reports no PRF support and returns no create-time output, returns an output that is not 32 bytes, or returns none on the fallback ceremony.

@throwsMeraError with code INPUT_INVALID when an explicit prfSalt is not 32 bytes.

@throwsMeraError with code CRYPTO_UNAVAILABLE when crypto.getRandomValues is unavailable.

@throwsMeraError with code PASSKEY_OPERATION_FAILED when WebAuthn is unavailable, cancelled, or returns an unexpected credential.

createPasskeyWithPrfOutput
,
function getPasskeyPrfOutput({ rpId, credential: allowCredential, prfSalt, timeout, webAuthnClient, }: getPasskeyPrfOutput.Options): Promise<getPasskeyPrfOutput.Result>

Requests a passkey PRF evaluation and returns the first output.

@paramoptions - Passkey PRF request inputs.

@returnsThe selected credential ID and first WebAuthn PRF output.

@remarks

Runs one assertion ceremony and shows one user-verification prompt.

The WebAuthn challenge is generated internally.

The default salt is sha256("mera.prf.salt.v1") and will not change across library versions. The PRF output is a deterministic function of the credential, rpId, and salt; a different salt yields an unrelated output.

The assertion requires user verification, and the requirement is not configurable. User verification is the authenticator's local check; the gesture depends on the platform (a biometric, a device PIN, or a password). Authenticators built on CTAP's hmac-secret keep two PRFs per credential, one for user-verified requests and one for the rest; WebAuthn exposes only the user-verified PRF and overrides a weaker userVerification setting when evaluating it, so a configurable setting could neither change the PRF output nor skip the check.

@seehttps://www.w3.org/TR/webauthn-3/#prf-extension WebAuthn: the PRF extension

@seehttps://www.w3.org/TR/webauthn-3/#enumdef-userverificationrequirement WebAuthn: UserVerificationRequirement

@throwsMeraError with code PRF_UNAVAILABLE when the authenticator does not return a usable 32-byte PRF output.

@throwsMeraError with code INPUT_INVALID when an explicit prfSalt is not 32 bytes, or credential.credentialId is empty or not canonical base64url.

@throwsMeraError with code CRYPTO_UNAVAILABLE when crypto.getRandomValues is unavailable.

@throwsMeraError with code PASSKEY_OPERATION_FAILED when WebAuthn is unavailable, cancelled, or returns an unexpected credential.

getPasskeyPrfOutput
,
} from "@category-labs/mera";
import {
const reactNativeWebAuthnClient: WebAuthnClient
reactNativeWebAuthnClient
} from "@category-labs/mera/react-native-webauthn-client";
const
const rpId: "account.example.com"
rpId
= "account.example.com";
const
const created: createPasskeyWithPrfOutput.Result
created
= await
function createPasskeyWithPrfOutput({ rp, user, timeout, prfSalt, webAuthnClient, }: createPasskeyWithPrfOutput.Options): Promise<createPasskeyWithPrfOutput.Result>

Creates a discoverable, user-verified passkey that requires WebAuthn PRF support and returns the first PRF output.

@paramoptions - Passkey creation inputs.

@returnsCredential metadata and the first PRF output.

@remarks

Runs one creation ceremony and shows one user-verification prompt. On authenticators that do not evaluate PRF during creation, a fallback assertion evaluates the same salt and shows a second prompt.

WebAuthn challenges and the credential's user handle (user.id) are generated internally, 32 random bytes each. An authenticator overwrites a discoverable credential that has the same rp.id and user.id, so a fresh handle per call adds a passkey instead of replacing one.

The credential is requested with fixed parameters: ES256 or RS256 key types, attestation "none", a required resident key, and required user verification (getPasskeyPrfOutput explains the requirement).

Any failure after the creation ceremony completes leaves the passkey on the authenticator, but the thrown error does not carry its metadata.

@throwsMeraError with code PRF_UNAVAILABLE when the authenticator reports no PRF support and returns no create-time output, returns an output that is not 32 bytes, or returns none on the fallback ceremony.

@throwsMeraError with code INPUT_INVALID when an explicit prfSalt is not 32 bytes.

@throwsMeraError with code CRYPTO_UNAVAILABLE when crypto.getRandomValues is unavailable.

@throwsMeraError with code PASSKEY_OPERATION_FAILED when WebAuthn is unavailable, cancelled, or returns an unexpected credential.

createPasskeyWithPrfOutput
({
rp: PasskeyRelyingParty

Relying party identity passed to WebAuthn. id is required so the fallback assertion can target the same relying party.

rp
: {
id: string

Relying party ID: the host the passkey is scoped to.

id
:
const rpId: "account.example.com"
rpId
,
name: string

Relying party name the authenticator may show.

name
: "Example" },
user: {
name: string;
displayName: string;
}

User identity passed to WebAuthn.

user
: {
name: string

User name displayed or stored by the authenticator.

name
: "account@example.com",
displayName: string

Human-readable display name for the authenticator UI.

displayName
: "Example account" },
webAuthnClient?: WebAuthnClient | undefined

Client that runs the WebAuthn ceremonies. Defaults to the built-in browser client, which calls navigator.credentials.

webAuthnClient
:
const reactNativeWebAuthnClient: WebAuthnClient
reactNativeWebAuthnClient
,
});
const
const signedIn: getPasskeyPrfOutput.Result
signedIn
= await
function getPasskeyPrfOutput({ rpId, credential: allowCredential, prfSalt, timeout, webAuthnClient, }: getPasskeyPrfOutput.Options): Promise<getPasskeyPrfOutput.Result>

Requests a passkey PRF evaluation and returns the first output.

@paramoptions - Passkey PRF request inputs.

@returnsThe selected credential ID and first WebAuthn PRF output.

@remarks

Runs one assertion ceremony and shows one user-verification prompt.

The WebAuthn challenge is generated internally.

The default salt is sha256("mera.prf.salt.v1") and will not change across library versions. The PRF output is a deterministic function of the credential, rpId, and salt; a different salt yields an unrelated output.

The assertion requires user verification, and the requirement is not configurable. User verification is the authenticator's local check; the gesture depends on the platform (a biometric, a device PIN, or a password). Authenticators built on CTAP's hmac-secret keep two PRFs per credential, one for user-verified requests and one for the rest; WebAuthn exposes only the user-verified PRF and overrides a weaker userVerification setting when evaluating it, so a configurable setting could neither change the PRF output nor skip the check.

@seehttps://www.w3.org/TR/webauthn-3/#prf-extension WebAuthn: the PRF extension

@seehttps://www.w3.org/TR/webauthn-3/#enumdef-userverificationrequirement WebAuthn: UserVerificationRequirement

@throwsMeraError with code PRF_UNAVAILABLE when the authenticator does not return a usable 32-byte PRF output.

@throwsMeraError with code INPUT_INVALID when an explicit prfSalt is not 32 bytes, or credential.credentialId is empty or not canonical base64url.

@throwsMeraError with code CRYPTO_UNAVAILABLE when crypto.getRandomValues is unavailable.

@throwsMeraError with code PASSKEY_OPERATION_FAILED when WebAuthn is unavailable, cancelled, or returns an unexpected credential.

getPasskeyPrfOutput
({
rpId: string

Relying party ID for the WebAuthn assertion.

rpId
,
webAuthnClient?: WebAuthnClient | undefined

Client that runs the WebAuthn ceremony. Defaults to the built-in browser client, which calls navigator.credentials.

webAuthnClient
:
const reactNativeWebAuthnClient: WebAuthnClient
reactNativeWebAuthnClient
,
});

Both results contain a credential ID and PRF output. Create passkey accounts shows how to derive and use accounts from the PRF output.

An app can use this client or provide its own WebAuthnClient.

A mobile app can store the credential ID and PRF output in secure device storage. It can then restore the account without another passkey request.