Orchestration SDKs

Step 4. Authenticating with external IdPs

PingOne Advanced Identity Cloud PingAM React Native

With your providers configured, you’re ready to wire up the authentication flow in your React Native app.

When a user reaches the social sign-on part of a journey, they see a list of the identity providers you’ve enabled, such as Apple, Facebook, and Google.

After they choose a provider, the module handles authentication. This uses the provider’s native SDK where available, or a browser redirect where native SDK support is not available on that platform.

To support this flow, your app needs to:

  • Create an ExternalIdpClient instance.

  • Handle SelectIdpCallback to render the provider list and record the user’s selection.

  • Handle IdpCallback to trigger the native sign-in flow for the chosen provider.

The sections below cover each step, followed by a full example and error handling reference.

Creating a client

Create an ExternalIdpClient instance using createExternalIdpClient.

Provide a redirectUri for devices that don’t support a native browser session (ASWebAuthenticationSession on iOS, Custom Tabs on Android), where the external IdP falls back to a redirect flow instead.

The value must match the URI scheme you registered in Step 2. Handling URI schemes:

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

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

  // Add optional logger
  logger: logger({ level: 'debug' }),
});

Handling callbacks

A journey that supports external IdPs will usually return two callback types in sequence:

Handling SelectIdpCallback

When the journey encounters a Select Identity Provider node, the client receives SelectIdpCallback. This callback lists the identity providers that are configured in your PingOne Advanced Identity Cloud tenant or PingAM server.

Within the SelectIdpCallback is a providers array. Each entry has a provider identifier string and an optional uiConfig object with display metadata.

Read the array to render a provider picker, then call selectProviderForJourney with the journey instance and the chosen provider value, followed by journey.next({}):

Handling SelectIdpCallback to render and select a provider
import type { JourneyInstance } from '@ping-identity/rn-types';
import type { JourneyNormalizedField, JourneyNode } from '@ping-identity/rn-journey';
import { useJourneyForm } from '@ping-identity/rn-journey';

type Provider = {
  provider: string;
  uiConfig?: {
    buttonDisplayName?: string;
    buttonImage?: string;
  };
};

function getProviders(field: JourneyNormalizedField): Provider[] {
  return (field.raw as { providers?: Provider[] }).providers ?? [];
}

function ProviderPicker({ journey, node }: { journey: JourneyInstance, node: JourneyNode }) {
  const { fields } = useJourneyForm(node);

  const selectIdpField = fields.find(f => f.ref.type === 'SelectIdpCallback');
  const providers = selectIdpField ? getProviders(selectIdpField) : [];

  // Render the identity providers, for example as buttons in your UI

  async function onProviderChosen(selected: string) {
    await externalIdp.selectProviderForJourney(journey, selected);
    await journey.next({});
  }
}

The provider value is the identifier string as configured in your Advanced Identity Cloud tenant or PingAM server. For example, 'google', 'facebook', or 'apple'.

The journey parameter is the JourneyInstance returned by useJourney.

If a journey node contains more than one SelectIdpCallback, use the index option to target the correct callback:

await externalIdp.selectProviderForJourney(journey, selected, { index: 1 });

Handling IdpCallback

When an authentication journey encounters a Social Provider Handler node your client receives an IdpCallback.

On receipt of the IdpCallback, call authorizeForJourney.

The module handles the authentication flow — whether through a native SDK or a browser redirect — and resolves the promise when complete. No deep-link listener or journey.resume() call is needed.

Call journey.next({}) after the promise resolves:

Calling authorizeForJourney and advancing the journey
await externalIdp.authorizeForJourney(journey);
await journey.next({});

If a journey node contains more than one SelectIdpCallback or IdpCallback, use the index option to target the correct callback:

await externalIdp.authorizeForJourney(journey, { index: 1 });

Full example

Handling external IdP callbacks end to end
import { createExternalIdpClient } from '@ping-identity/rn-external-idp';
import type { JourneyInstance, NodeCallback } from '@ping-identity/rn-types';

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

async function handleExternalIdpNode(
  journey: JourneyInstance,
  callbacks: NodeCallback[],
): Promise<void> {
  for (const cb of callbacks) {
    if (cb.type === 'SelectIdpCallback') {
      const provider = getUserSelectedProvider(); // e.g. 'google'
      await externalIdp.selectProviderForJourney(journey, provider);
    }

    if (cb.type === 'IdpCallback') {
      await externalIdp.authorizeForJourney(journey);
    }
  }

  await journey.next({});
}

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.authorizeForJourney(journey);
} 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.

This can occur when the corresponding native SDK is absent, or when a browser redirect flow is required but no valid redirectUri was provided.

EXTERNAL_IDP_CALLBACK_NOT_FOUND

The module could not find a matching callback in the journey 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.