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
ExternalIdpClientinstance. -
Handle
SelectIdpCallbackto render the provider list and record the user’s selection. -
Handle
IdpCallbackto 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:
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({}):
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
|
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:
await externalIdp.authorizeForJourney(journey);
await journey.next({});
|
If a journey node contains more than one
|
Full example
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:
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
redirectUriwas 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.