Orchestration SDKs

Step 4. Authenticating with external IdPs

PingOne React Native

With your providers configured, you’re ready to wire up social sign-on in your React Native app.

When a user reaches the social sign-on part of a DaVinci flow, the flow returns a ContinueNode containing one IdpCollector for each external identity provider you configured in Configuring social sign-on in PingOne.

To support this flow, your app needs to:

  • Create an ExternalIdpClient instance.

  • Render a sign-in button for each IdpCollector in the node.

  • Call authorizeForDaVinci when the user chooses a provider, then advance the flow with daVinci.next({ collectors: [] }).

The sections below cover each step, followed by error handling.

Creating a client

Create an ExternalIdpClient instance using the createExternalIdpClient function.

Provide a redirectUri that matches the URI scheme you registered in Step 2. Handling URI schemes.

The client is reusable, so create it once and share it across your components, for example with a useMemo hook:

Creating an ExternalIdpClient instance
import { createExternalIdpClient } from '@ping-identity/rn-external-idp';

const externalIdp = createExternalIdpClient({
  redirectUri: 'myapp://callback',
});

// The client is reusable. For example, inside a component:
// const externalIdp = useMemo(
//   () => createExternalIdpClient({ redirectUri: 'myapp://callback' }),
//   [],
// );

On Android, when you omit the redirectUri, the module falls back to the appRedirectUriScheme manifest placeholder you set in Step 2. Handling URI schemes.

Rendering the social sign-on buttons

Render one sign-in button for each IdpCollector in the node, so users can choose how to authenticate:

An app with three external IdP options; Apple, Facebook, and Google.
Figure 1. An app with three external IdP options: Apple, Facebook, and Google.

The useDaVinciForm hook manages collector form state and submit planning for the active DaVinci node.

Create the form with the node from useDaVinci, and pass handledCollectorTypes so the social sign-on collectors are excluded from blocking submit issues:

Configuring useDaVinciForm to handle social sign-on collectors
import { useDaVinci, useDaVinciForm } from '@ping-identity/rn-davinci';

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

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

Without handledCollectorTypes, each SOCIAL_LOGIN_BUTTON 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 SOCIAL_LOGIN_BUTTON in handledCollectorTypes, your app declares that it handles these collectors itself, and form.canSubmit reflects the readiness of the remaining form fields.

DaVinci flows represent each social sign-on option as an IdpCollector collector with the type SOCIAL_LOGIN_BUTTON.

What fields are available in an IdpCollector?

The IdpCollector exposes the following fields:

Field Type Description

key

string

Stable server-assigned IdP identifier.

Use this value as the form field key and as the React list key when rendering buttons.

type

'SOCIAL_LOGIN_BUTTON'

The collector type.

Always SOCIAL_LOGIN_BUTTON for social sign-on.

label

string

Human-readable button label, for example Sign in with Google.

idpId

string

Server IdP identifier.

The same value as key.

idpType

'APPLE', 'FACEBOOK', 'GOOGLE', or another provider string

The provider type.

Use this value to choose an icon or brand styling for the button.

APPLE is available on iOS only.

idpEnabled

boolean

Whether the IdP is currently enabled.

Disable the button when this is false.

link

string, optional

The IdP authentication URL.

Informational only; your app does not use it directly.

Render one button for each social sign-on collector, using the label and idpType fields from each entry of form.fields to style it:

Rendering a social sign-on button for each IdpCollector
const idpFields = form.fields.filter((field) => field.type === 'SOCIAL_LOGIN_BUTTON');

return idpFields.map((collector) => (
  <Button
    key={collector.key}
    title={collector.label}
    onPress={() => onIdpAuthorize(collector)}
    disabled={!collector.idpEnabled}
  />
));

Authorizing with the chosen provider

When the user taps a social sign-on button, call authorizeForDaVinci with your ExternalIdpClient and the DaVinci client.

If the node contains more than one IdpCollector, pass the index of the collector the user chose:

Calling authorizeForDaVinci and advancing the flow
import type { IdpCollector } from '@ping-identity/rn-davinci';

async function onIdpAuthorize(collector: IdpCollector): Promise<void> {
  const idpFields = form.fields.filter((f) => f.type === 'SOCIAL_LOGIN_BUTTON');
  const index = idpFields.findIndex((f) => f.key === collector.key);

  try {
    await externalIdp.authorizeForDaVinci(daVinciClient, { index });
    await next({ collectors: [] });
  } catch (error) {
    // Handle the error, see below
  }
}

authorizeForDaVinci returns void, not a token.

The token is carried into the subsequent daVinci.next({ collectors: [] }) request by a request interceptor inside the native SDK.

This is why the call to next() passes an empty collectors array. The flow advances on its own, with the token attached by the native layer.

When authorizeForDaVinci resolves, the user has completed authentication with the external IdP, and the next() call advances the DaVinci flow to the next node.

Error handling

All promise rejections from the External IdP module throw an ExternalIdpError instance.

Use instanceof to narrow the type:

Catching and inspecting ExternalIdpError
import { ExternalIdpError } from '@ping-identity/rn-external-idp';

try {
  await externalIdp.authorizeForDaVinci(daVinciClient, { index: 0 });
  await next({ collectors: [] });
} catch (err) {
  if (err instanceof ExternalIdpError) {
    console.log(err.code, err.message);
  }
}

The error codes are:

EXTERNAL_IDP_AUTHORIZE_ERROR

The provider returned an error during authorization.

EXTERNAL_IDP_CANCELLED

The user cancelled the sign-in flow.

EXTERNAL_IDP_UNSUPPORTED_PROVIDER

The provider is not supported on this platform.

In DaVinci flows the module falls back to a browser redirect when a native provider SDK is not linked, so this error is uncommon.

The most common cause is a misconfigured native provider SDK, for example a Google client ID that does not match your app’s package name or signing certificate.

EXTERNAL_IDP_CALLBACK_NOT_FOUND

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

EXTERNAL_IDP_CONFIG_ERROR

The client configuration is invalid.

EXTERNAL_IDP_ACTIVITY_UNAVAILABLE

(Android only) The Android activity required to launch the sign-in flow is unavailable.

EXTERNAL_IDP_WINDOW_UNAVAILABLE

(iOS only) The window required to present the sign-in flow is unavailable.