Orchestration SDKs

Integrating FIDO DaVinci flows into React Native apps

PingOne React Native

The FIDO module provides native-backed FIDO capabilities for React Native apps, including registering and authenticating with passkeys.

Before you begin

Ensure you have prepared PingOne for FIDO authentication in React Native apps before completing the steps on this page.

Step 1. Installing modules

The FIDO module for React Native is available as the @ping-identity/rn-fido npm package.

The module requires the @ping-identity/rn-core package. Install both packages in your React Native project:

  • yarn

  • npm

yarn add @ping-identity/rn-core @ping-identity/rn-fido
npm install @ping-identity/rn-core @ping-identity/rn-fido

Installing native dependencies on iOS

After installing the package, install the native iOS dependencies using CocoaPods:

cd ios && pod install

Adding optional dependencies on Android

Gradle resolves the Android native dependencies automatically.

Optionally, add the following dependencies to your app’s build.gradle if needed:

  • If your app targets Android API 33 (Android 13) or older, add androidx.credentials:credentials-play-services-auth to ensure FIDO functions correctly on those devices.

  • If your app needs to support non-discoverable FIDO credentials or physical security keys, add com.google.android.gms:play-services-fido.

Step 2. Creating the FIDO client

Create a FIDO client by calling createFidoClient().

Create the client once and reuse it for the lifetime of the relevant screen or session, for example with a useMemo hook:

Creating the FIDO client
import { createFidoClient } from '@ping-identity/rn-fido';

const fidoClient = createFidoClient();

You can call createFidoClient() without arguments.

The client does not require configuration for the DaVinci ceremony methods, registerForDaVinci() and authenticateForDaVinci(). These methods build their own native FIDO client and use the logger configured in the DaVinci workflow, so client-level options such as logger have no effect on them.

Step 3. Handling FIDO2 collectors in a DaVinci flow

When a DaVinci flow reaches a FIDO step, the flow returns a ContinueNode containing a FIDO2 collector.

DaVinci flows represent each FIDO operation as a single FIDO2 collector, and the collector’s action property tells you which operation it performs:

REGISTER

A registration collector. The user is registering a new passkey with the flow.

AUTHENTICATE

An authentication collector. The user is authenticating with an existing passkey.

To support this flow, your app needs to:

  • Create the form with the node from useDaVinci, and pass FIDO2 in handledCollectorTypes.

  • Render a passkey button for each FIDO2 collector in the node.

  • Call registerForDaVinci or authenticateForDaVinci depending on the collector’s action, then advance the flow with daVinci.next({ collectors: [] }).

Configuring useDaVinciForm to handle FIDO collectors

The useDaVinciForm hook manages form state for the collectors on the active DaVinci node, and plans what the app submits when the form is complete.

Create the form with the node from useDaVinci, and pass the FIDO2 collector type in handledCollectorTypes so the FIDO collectors are excluded from blocking submit issues:

Configuring useDaVinciForm to handle FIDO collectors
import { useDaVinci, useDaVinciForm } from '@ping-identity/rn-davinci';
import { fidoCollectorType } from '@ping-identity/rn-fido';

const { node, next } = useDaVinci(daVinciClient);

const form = useDaVinciForm(node, {
  handledCollectorTypes: new Set([fidoCollectorType]),
});

Without handledCollectorTypes, each FIDO2 collector raises an INTEGRATION_REQUIRED issue and forces form.canSubmit to false, because the module treats these collectors as requiring client-side integration.

When you list FIDO2 in handledCollectorTypes, your app declares that it handles these collectors itself, and form.canSubmit reflects the readiness of the remaining form fields.

What fields are available in a FIDO2 collector?

The FIDO collector exposes the following fields:

Field Type Description

key

string

Stable server-assigned identifier used as the collector key.

type

'FIDO2'

The collector type.

Always FIDO2 for FIDO collectors.

action

'REGISTER' or 'AUTHENTICATE'

The ceremony action.

Use this value to decide whether to call registerForDaVinci() or authenticateForDaVinci().

label

string

Human-readable label rendered for the collector.

required

boolean

Whether the collector must be completed before submission.

trigger

string, optional

Android-only trigger string surfaced by the native collector.

The iOS collector does not expose this field.

publicKeyCredentialCreationOptions

object, optional

WebAuthn public key credential creation options returned by the server, on registration collectors.

publicKeyCredentialRequestOptions

object, optional

WebAuthn public key credential request options returned by the server, on authentication collectors.

raw

object, optional

Original server-side field JSON when available.

Step 4. Registering FIDO authenticators

To register a FIDO authenticator, call registerForDaVinci() on the FIDO client with the active DaVinci client.

The method runs the native platform passkey ceremony, and the native layer submits the resulting attestation to the flow before the method returns:

Registering a FIDO authenticator in a DaVinci flow
async function handleFidoCeremony(collector) {
  if (collector.action === 'REGISTER') {
    await fidoClient.registerForDaVinci(daVinciClient, { index });
    await next({ collectors: [] });
  }
}

The daVinciClient parameter is a DaVinci client created with createDaVinciClient(). Learn more in Configuring the DaVinci module in React Native.

If the node contains more than one FIDO2 registration collector, pass the zero-based index of the collector the user chose.

The attestation payload returned by registerForDaVinci is informational only.

The native layer submits the credential to the DaVinci flow itself, which is why the call to next() passes an empty collectors array.

Step 5. Authenticating using a FIDO authenticator

To authenticate using a registered FIDO authenticator, call authenticateForDaVinci() on the FIDO client.

The method runs the native platform passkey ceremony, and the native layer submits the resulting assertion to the flow before the method returns:

Authenticating with a FIDO authenticator in a DaVinci flow
async function handleFidoCeremony(collector) {
  if (collector.action === 'AUTHENTICATE') {
    await fidoClient.authenticateForDaVinci(daVinciClient, { index });
    await next({ collectors: [] });
  }
}

If the node contains more than one FIDO2 authentication collector, pass the zero-based index of the collector the user chose.

Because both ceremony methods submit their result through the native layer, a common pattern is to branch on the collector’s action in a single handler and advance the flow after the ceremony resolves:

Handling both FIDO actions in one handler
import type { FidoCollector } from '@ping-identity/rn-fido';

async function handleFidoCeremony(collector: FidoCollector): Promise<void> {
  const fidoFields = form.fields.filter(
    (f) => f.type === fidoCollectorType &&
      (f as FidoCollector).action === collector.action,
  );
  const index = fidoFields.findIndex((f) => f.key === collector.key);

  try {
    if (collector.action === 'REGISTER') {
      await fidoClient.registerForDaVinci(daVinciClient, { index });
    } else {
      await fidoClient.authenticateForDaVinci(daVinciClient, { index });
    }
    await next({ collectors: [] });
  } catch (err) {
    // Handle the error, see below
  }
}

When a node contains both registration and authentication collectors, compute the index within the subset of collectors matching the ceremony action, because the native resolvers index collectors separately for registration and authentication.

Step 6. Handling cancellation and errors

When a FIDO operation fails or is cancelled, the SDK throws a FidoError.

Use the code property to distinguish cancellation from other failures:

Handling FIDO cancellation and errors
import { FidoError } from '@ping-identity/rn-fido';

try {
  await handleFidoCeremony(collector);
} catch (err) {
  if (err instanceof FidoError) {
    if (err.code === 'FIDO_AUTHENTICATE_CANCELLED') {
      // Non-fatal. On Android this also fires when the device has no
      // enrolled passkey (NoCredentialException), in which case routing
      // the user to registration may be more appropriate than offering
      // a fallback authentication path.
      return;
    }
    // For other errors, fall through and advance the flow
    // so the server can route to its configured failure branch
  }
  await next({ collectors: [] });
}

Error codes

Error code Description

FIDO_ERROR

A general FIDO error that does not fall into a more specific category.

FIDO_REGISTER_ERROR

Registration failed. The platform reported an error creating the credential.

FIDO_AUTHENTICATE_ERROR

Authentication failed due to a platform or server-side error.

FIDO_AUTHENTICATE_CANCELLED

The FIDO authentication ceremony ended without an assertion. This can be caused by any of the following:

  • The user dismissed the prompt

  • The device has no eligible passkey (Android)

  • The platform reported a generic authorization failure.

    iOS reports failures and cancellations identically.

You can treat this as non-fatal and offer a fallback authentication path.

FIDO_ACTIVITY_UNAVAILABLE

The Android Activity required to launch the FIDO UI is unavailable.

FIDO_WINDOW_UNAVAILABLE

The iOS window required to present the FIDO UI is unavailable.

FIDO_COLLECTOR_NOT_FOUND

The module could not find a matching FIDO2 collector in the DaVinci node.