This package provides a native-backed FIDO bridge for React Native.
useJourneyForm integrationNote: This module requires that the
@ping-identity/rn-coremodule is already set up and installed.
# Install & setup the core module
yarn add @ping-identity/rn-core
# Install the rn-fido module
yarn add @ping-identity/rn-fido
# If you are developing your app using iOS, run this command
cd ios && pod install
Optional integration packages:
yarn add @ping-identity/rn-logger
https://<rp-domain>/.well-known/assetlinks.json.assetlinks.json contains your Android package name and signing cert fingerprint(s).androidx.credentials:credentials-play-services-auth.com.google.android.gms:play-services-fido.webcredentials:<rp-domain>).https://<rp-domain>/.well-known/apple-app-site-association.Use createFidoClient(config?) and call operations on the returned client.
import { createFidoClient } from '@ping-identity/rn-fido';
import { logger } from '@ping-identity/rn-logger';
const log = logger({ level: 'debug' });
const fido = createFidoClient({
logger: log,
android: {
useFido2Client: true,
},
});
const registrationResult = await fido.register({
challenge: 'base64url-challenge',
rp: { id: 'example.com', name: 'Example Inc.' },
user: {
id: 'base64url-user-id',
name: 'user@example.com',
displayName: 'Example User',
},
pubKeyCredParams: [{ type: 'public-key', alg: -7 }],
});
const authenticationResult = await fido.authenticate({
challenge: 'base64url-challenge',
rpId: 'example.com',
allowCredentials: [],
});
If you install the logger package, pass a JS logger instance created via
@ping-identity/rn-logger.
If the logger package is not installed/configured, do not pass logger values in FIDO config.
JavaScript-side FIDO logs use this logger on both platforms.
Native logger forwarding applies to standalone operations on both platforms.
Journey and DaVinci collector ceremonies retain their workflow-configured native logger.
import { createFidoClient } from '@ping-identity/rn-fido';
import { logger } from '@ping-identity/rn-logger';
const jsLogger = logger({ level: 'debug' });
const fido = createFidoClient({
logger: jsLogger,
});
import { createFidoClient } from '@ping-identity/rn-fido';
const fidoA = createFidoClient({
android: { useFido2Client: true },
});
const fidoB = createFidoClient({
android: { useFido2Client: false },
});
await fidoA.register({ challenge: '...' });
await fidoB.authenticate({ challenge: '...' });
Run Journey FIDO callbacks explicitly before journey.next(...).
import { createFidoClient } from '@ping-identity/rn-fido';
const fido = createFidoClient();
if (node.type === 'ContinueNode') {
for (const callback of node.callbacks ?? []) {
if (callback.type === 'FidoRegistrationCallback') {
await fido.registerForJourney(journey, {
index: 0,
deviceName: 'My Device',
});
}
if (callback.type === 'FidoAuthenticationCallback') {
await fido.authenticateForJourney(journey, { index: 0 });
}
}
await journey.next({});
}
FIDO2 DaVinci collectors use one collector type and an action discriminator:
action: 'REGISTER' exposes creation options, while action: 'AUTHENTICATE'
exposes request options. Create a FIDO client before starting or normalizing
the DaVinci flow — createFidoClient registers fidoCollectorType
('FIDO2') with the integration registry and eagerly registers the native
collector serializer, so nodes mapped before the first ceremony still carry
action and the WebAuthn options payload.
Run the ceremony, then advance the DaVinci flow with an empty collector input:
import { useDaVinciForm } from '@ping-identity/rn-davinci';
import {
createFidoClient,
fidoCollectorType,
type FidoCollector,
} from '@ping-identity/rn-fido';
const fido = createFidoClient();
const form = useDaVinciForm(node, {
handledCollectorTypes: new Set([fidoCollectorType]),
});
const collector = node.collectors[0] as FidoCollector;
if (collector.action === 'REGISTER') {
await fido.registerForDaVinci(daVinci, { index: 0 });
} else {
await fido.authenticateForDaVinci(daVinci, { index: 0 });
}
// The native collector retains the attestation or assertion for submission.
await daVinci.next({ collectors: [] });
When using useDaVinciForm, include fidoCollectorType in
handledCollectorTypes after creating the FIDO client. Do not pass the FIDO
collector key to next(). The initial DaVinci integration uses native ceremony
defaults and does not expose React Native customization options.
The optional index selects among multiple FIDO2 collectors with the same
action. The methods return the native attestation or assertion payload for
informational use; the native collector submits it when the flow advances.
useJourneyForm integrationWhen using useJourneyForm, pass handledCallbackTypes so FIDO fields are excluded from
blocking submit issues. Run each integration, then submit when form.canSubmit is true.
import { useJourney, useJourneyForm } from '@ping-identity/rn-journey';
import { createFidoClient } from '@ping-identity/rn-fido';
import { nativeExtensionCallbackType } from '@ping-identity/rn-types';
const [node, actions] = useJourney(client);
const form = useJourneyForm(node, {
handledCallbackTypes: new Set([
nativeExtensionCallbackType.FidoRegistrationCallback,
nativeExtensionCallbackType.FidoAuthenticationCallback,
]),
});
const fido = createFidoClient();
for (const field of form.fields) {
if (field.ref.type === nativeExtensionCallbackType.FidoRegistrationCallback) {
await fido.registerForJourney(journey, { index: field.ref.typeIndex });
}
if (
field.ref.type === nativeExtensionCallbackType.FidoAuthenticationCallback
) {
await fido.authenticateForJourney(journey, { index: field.ref.typeIndex });
}
}
if (form.canSubmit) {
await actions.next(form.input);
}
import { createFidoClient } from '@ping-identity/rn-fido';
import type {
FidoClient,
FidoConfig,
FidoRegistrationOptions,
FidoRegistrationResult,
FidoAuthenticationOptions,
FidoAuthenticationResult,
FidoJourneyRegistrationOptions,
FidoJourneyAuthenticationOptions,
FidoJourneyResult,
FidoDaVinciRegistrationOptions,
FidoDaVinciAuthenticationOptions,
FidoDaVinciResult,
DaVinciInstance,
JourneyInstance,
} from '@ping-identity/rn-fido';
function createFidoClient(config?: FidoConfig): FidoClient;
interface FidoClient {
register(options: FidoRegistrationOptions): Promise<FidoRegistrationResult>;
authenticate(
options: FidoAuthenticationOptions,
): Promise<FidoAuthenticationResult>;
registerForJourney(
journey: JourneyInstance,
options?: FidoJourneyRegistrationOptions,
): Promise<FidoJourneyResult>;
authenticateForJourney(
journey: JourneyInstance,
options?: FidoJourneyAuthenticationOptions,
): Promise<FidoJourneyResult>;
registerForDaVinci(
daVinci: DaVinciInstance,
options?: FidoDaVinciRegistrationOptions,
): Promise<FidoDaVinciResult>;
authenticateForDaVinci(
daVinci: DaVinciInstance,
options?: FidoDaVinciAuthenticationOptions,
): Promise<FidoDaVinciResult>;
}
Rejected promises throw a FidoError instance, which extends PingError extends Error. Use instanceof FidoError to narrow in catch blocks.
Stable error codes:
FIDO_ERRORFIDO_REGISTER_ERRORFIDO_AUTHENTICATE_ERRORFIDO_AUTHENTICATE_CANCELLEDFIDO_ACTIVITY_UNAVAILABLE (Android)FIDO_WINDOW_UNAVAILABLE (iOS)FIDO_CALLBACK_NOT_FOUNDFIDO_COLLECTOR_NOT_FOUNDandroid.useFido2Client is an Android-only override.
undefined (default): native SDK auto-detection/default behavior.true: force Google Play Services FIDO2 APIs.false: force Android Credential Manager APIs.FidoClient configuration.Activity for FIDO calls.UIWindowScene/ASPresentationAnchor for FIDO calls.Full passkey E2E strategy (including OS-level credential surfaces outside app UI) is still to be determined.
This project is licensed under the MIT License - see the LICENSE file for details