Skill Parameters
When invoked with no arguments, run the wizard. With arguments, generate inline.
No-arg Invocation — Wizard Mode
Step W1 — Determine intent using AskUserQuestion:
"What would you like to do?"
Options:
A) Scaffold a new React Native project — complete working app with Ping SDK wired in
B) Add to an existing app — generate only the files to drop into your project
C) Browse the reference guide — show the full integration guide
D) Something else — let me describe what I need
- A/B → Step W1b
- C → read and display references/integration-guide.md. Stop.
- D → follow-up free-text question, route accordingly.
Step W1b — Journey export offer (options A and B only).
Ask: "Do you have a Journey export JSON? If so, paste it and I'll analyse it to identify the exact callbacks your Journey uses and pre-populate the callback tier."
- If provided: run Section 7 (Journey Export Analysis, references/journey-export-analysis.md) before Step W2. Pre-populate
journeyName and callbackTier from the analysis. Ask Step W2.5 (callback mode) as usual — callbackMode cannot be inferred from the export and must still be asked.
- If not provided: continue to Step W2 as normal.
Step W2 — Flow type using AskUserQuestion:
"Which authentication flow do you need?"
Options:
1) Journey — native in-app UI, targets PingAM / PingOne AIC
2) OIDC Web — browser-based login, any OIDC provider
3) Journey + OIDC — both flows in one app, FlowPicker as the entry screen
- 1 → store
flowType = 'journey'
- 2 → store
flowType = 'oidc'
- 3 → store
flowType = 'both'; collect parameters for both Journey and OIDC in W3; ask W2.5 and W2.6 as normal for the Journey portion; generate both sets of screens plus FlowPicker; install combined package set (Journey full tier + rn-oidc)
Step W2.5 — Callback handling (Journey only, skip when flowType = 'oidc') using AskUserQuestion:
"How would you like to handle Journey callbacks?"
Options:
A) Managed (Recommended) — useJourneyForm handles field state, validation,
and payload building. Simpler code; less boilerplate.
B) Manual — useJourney only. You control field state and
build the submit payload yourself. More flexibility, more code.
Store the answer as callbackMode (managed or manual). Used in step 4 to pick the correct CallbackRenderer template.
Step W2.6 — Callback tier (Journey only) using AskUserQuestion:
"Which callbacks does your Journey use?"
Options:
A) Basic — username, password, text, choice, T&C, KBA.
No extra packages needed beyond rn-journey.
B) Standard — Basic + FIDO passkeys, device binding, device profile.
Adds: rn-fido, rn-binding, rn-device-profile.
C) Full — Standard + social / external IdP (Google, Apple, Facebook).
Adds: rn-external-idp.
Store the answer as callbackTier (basic, standard, or full). Used in steps 4 and 5 to pick the correct templates and install commands.
Step W3 — Collect configuration.
Ask all required parameters in a single AskUserQuestion. Show defaults where they exist. Do not generate until every required field has a value.
Common parameters (both flows):
| Parameter |
Required |
Default |
Description |
appName |
Scaffold only |
PingDemo |
App name. Only ask when intent is A (scaffold). For intent B (add to existing), skip this — use PingDemo as default and never prompt for it. |
clientId |
Yes |
— |
OAuth 2.0 Client ID |
redirectUri |
Yes |
— |
OAuth 2.0 redirect URI (custom scheme, e.g. com.example.app://callback) |
discoveryEndpoint |
Yes |
— |
Full .well-known/openid-configuration URL |
scopes |
No |
openid profile email |
Space-separated OAuth 2.0 scopes |
Journey-only additional parameters:
| Parameter |
Required |
Default |
Description |
serverUrl |
Yes |
— |
PingAM/AIC base URL, no trailing / |
realm |
No |
alpha |
Authentication realm |
cookieName |
No |
iPlanetDirectoryPro |
Session cookie name |
journeyName |
No |
Login |
Journey tree name |
Validation rules:
redirectUri must use a custom scheme (not http:// or https://).
discoveryEndpoint must start with https:// and end with /.well-known/openid-configuration.
scopes must include openid. If missing, prepend it and warn.
serverUrl (Journey) must start with https:// and have no trailing /.
Step W3.5 — Output path. Ask where to write the files using AskUserQuestion:
"Where should the files be written?"
Options:
A) Current working directory — write files to the project root
B) Specify a path — I'll provide an absolute or relative path
C) Print to chat only — show the code inline, don't write to disk
- A → use the current working directory as
outputDir.
- B → follow-up free-text question: "Enter the output directory path:". Use that value as
outputDir.
- C → set
outputDir = null (inline output only).
Scaffold intent note: When intent is A (Scaffold a new project) and outputDir is set, the React Native project will be initialised as <outputDir>/<appName>/. All Ping SDK files are written into that subdirectory. The final structure is <outputDir>/<appName>/ containing the generated project.
Step W4 — Confirm and generate. Summarise collected values (including output path) in a short table, ask "Ready to generate — does this look right?", then proceed on confirmation.
If intent is A (Scaffold a new project) and outputDir is set:
Run the React Native scaffold command first using the Bash tool:
npx @react-native-community/cli@latest init <AppName> --directory <outputDir>/<AppName>
Wait for it to complete before writing any files. If it fails, report the error and stop.
Set projectDir = <outputDir>/<AppName>.
Apply Ping Identity branding and copy templates — always do this before writing any screen files.
- Read
assets/PingTheme.tsx.template from this skill and write it to <projectDir>/src/theme/PingTheme.tsx (no substitutions needed).
- Copy
assets/ping_logo.png from this skill to <projectDir>/src/assets/ping_logo.png.
- Create the directory
<projectDir>/src/callbacks/.
All generated screens import branded components from ../theme/PingTheme — never inline ad-hoc styles.
Branded components available: PingPrimaryButton, PingHeaderView, PingTextField, PingSecureField, PingErrorMessage, PingErrorCard, PingLoadingOverlay. Color tokens: PingColors.red, PingColors.redDark, PingColors.textField, etc.
Write screens and callbacks from templates — read each template from this skill's assets/ directory and write it to the project. Do not generate these files from memory; always read the template first.
Callback components — Basic tier (all tiers write these):
assets/callbacks/NameCallbackView.tsx.template → src/callbacks/NameCallbackView.tsx
assets/callbacks/ValidatedUsernameCallbackView.tsx.template → src/callbacks/ValidatedUsernameCallbackView.tsx
assets/callbacks/PasswordCallbackView.tsx.template → src/callbacks/PasswordCallbackView.tsx
assets/callbacks/ValidatedPasswordCallbackView.tsx.template → src/callbacks/ValidatedPasswordCallbackView.tsx
assets/callbacks/TextInputCallbackView.tsx.template → src/callbacks/TextInputCallbackView.tsx
assets/callbacks/StringAttributeInputCallbackView.tsx.template → src/callbacks/StringAttributeInputCallbackView.tsx
assets/callbacks/NumberAttributeInputCallbackView.tsx.template → src/callbacks/NumberAttributeInputCallbackView.tsx
assets/callbacks/BooleanAttributeInputCallbackView.tsx.template → src/callbacks/BooleanAttributeInputCallbackView.tsx
assets/callbacks/TextOutputCallbackView.tsx.template → src/callbacks/TextOutputCallbackView.tsx
assets/callbacks/SuspendedTextOutputCallbackView.tsx.template → src/callbacks/SuspendedTextOutputCallbackView.tsx
assets/callbacks/ChoiceCallbackView.tsx.template → src/callbacks/ChoiceCallbackView.tsx
assets/callbacks/ConfirmationCallbackView.tsx.template → src/callbacks/ConfirmationCallbackView.tsx
assets/callbacks/TermsAndConditionsCallbackView.tsx.template → src/callbacks/TermsAndConditionsCallbackView.tsx
assets/callbacks/KbaCreateCallbackView.tsx.template → src/callbacks/KbaCreateCallbackView.tsx
assets/callbacks/PollingWaitCallbackView.tsx.template → src/callbacks/PollingWaitCallbackView.tsx
assets/callbacks/UnsupportedCallbackView.tsx.template → src/callbacks/UnsupportedCallbackView.tsx
Callback components — Standard tier (write these when callbackTier = standard or full):
assets/callbacks/ConsentMappingCallbackView.tsx.template → src/callbacks/ConsentMappingCallbackView.tsx
assets/callbacks/FidoRegistrationCallbackView.tsx.template → src/callbacks/FidoRegistrationCallbackView.tsx
assets/callbacks/FidoAuthenticationCallbackView.tsx.template → src/callbacks/FidoAuthenticationCallbackView.tsx
assets/callbacks/DeviceBindingCallbackView.tsx.template → src/callbacks/DeviceBindingCallbackView.tsx
assets/callbacks/DeviceSigningVerifierCallbackView.tsx.template → src/callbacks/DeviceSigningVerifierCallbackView.tsx
assets/callbacks/DeviceProfileCallbackView.tsx.template → src/callbacks/DeviceProfileCallbackView.tsx
Callback components — Full tier (write these when callbackTier = full):
assets/callbacks/SelectIdpCallbackView.tsx.template → src/callbacks/SelectIdpCallbackView.tsx
Screen files (Journey flow) — pick template based on callbackMode + callbackTier:
callbackMode |
callbackTier |
Template to use |
| managed |
basic |
assets/CallbackRenderer.form.basic.tsx.template |
| managed |
standard |
assets/CallbackRenderer.form.standard.tsx.template |
| managed |
full |
assets/CallbackRenderer.form.tsx.template |
| manual |
basic |
assets/CallbackRenderer.basic.tsx.template |
| manual |
standard |
assets/CallbackRenderer.standard.tsx.template |
| manual |
full |
assets/CallbackRenderer.tsx.template |
Write the chosen template to <projectDir>/src/screens/CallbackRenderer.tsx.
- Read
assets/LoginScreen.tsx.template → write to <projectDir>/src/screens/LoginScreen.tsx
- Read
assets/HomeScreen.tsx.template → write to <projectDir>/src/screens/HomeScreen.tsx
Screen files (OIDC flow):
- Read
assets/LoginScreen.oidc.tsx.template → write to <projectDir>/src/screens/LoginScreen.tsx
- Read
assets/HomeScreen.oidc.tsx.template → write to <projectDir>/src/screens/HomeScreen.tsx
After writing templates, substitute <AppName> placeholders in LoginScreen.tsx and HomeScreen.tsx with the actual app name.
These files are still generated (they contain user-supplied config values):
<projectDir>/src/<AppName>JourneyClient.ts (or OidcClient.ts for OIDC)
Full tier only — also export idpClient from the Journey client file:
import { createExternalIdpClient } from '@ping-identity/rn-external-idp';
export const idpClient = createExternalIdpClient();
SelectIdpCallbackView imports idpClient from this file.
Overwrite <projectDir>/App.tsx with a React Navigation stack. All Ping providers must wrap the single NavigationContainer — never use multiple NavigationContainer instances or nest providers inside screen components. A single flat stack gives every screen a back button automatically.
Journey flow:
import React from 'react';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { JourneyProvider } from '@ping-identity/rn-journey';
import journeyClient from './<AppName>JourneyClient';
import LoginScreen from './screens/LoginScreen';
import HomeScreen from './screens/HomeScreen';
export type RootStackParamList = {
Login: undefined;
Home: undefined;
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
return (
<JourneyProvider client={journeyClient}>
<NavigationContainer>
<Stack.Navigator initialRouteName="Login">
<Stack.Screen name="Login" component={LoginScreen} options={{ headerShown: false }} />
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Profile' }} />
</Stack.Navigator>
</NavigationContainer>
</JourneyProvider>
);
}
OIDC flow:
import React, { useMemo } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { OidcProvider, createOidcClient, createOidcWebClient } from '@ping-identity/rn-oidc';
import LoginScreen from './screens/LoginScreen';
import HomeScreen from './screens/HomeScreen';
export type RootStackParamList = {
Login: undefined;
Home: undefined;
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
const client = useMemo(() => {
const oidcClient = createOidcClient({
clientId: '<clientId>',
discoveryEndpoint: '<discoveryEndpoint>',
redirectUri: '<redirectUri>',
scopes: ['openid', 'profile', 'email'],
});
return createOidcWebClient(oidcClient);
}, []);
return (
<OidcProvider client={client}>
<NavigationContainer>
<Stack.Navigator initialRouteName="Login">
<Stack.Screen name="Login" component={LoginScreen} options={{ headerShown: false }} />
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Profile' }} />
</Stack.Navigator>
</NavigationContainer>
</OidcProvider>
);
}
Both flows (flow picker): When scaffolding both Journey and OIDC, use a single stack with a FlowPicker screen as the initial route. Both providers sit above the single NavigationContainer. The OidcProvider client is created in useMemo at the App level — never inside a screen component.
export type RootStackParamList = {
FlowPicker: undefined;
JourneyLogin: undefined;
JourneyHome: undefined;
OidcLogin: undefined;
OidcHome: undefined;
};
export default function App() {
const oidcClient = useMemo(() => createOidcWebClient(createOidcClient({...})), []);
return (
<JourneyProvider client={journeyClient}>
<OidcProvider client={oidcClient}>
<NavigationContainer>
<Stack.Navigator initialRouteName="FlowPicker">
<Stack.Screen name="FlowPicker" component={FlowPicker} options={{ headerShown: false }} />
<Stack.Screen name="JourneyLogin" component={LoginScreen} options={{ title: 'Sign In' }} />
<Stack.Screen name="JourneyHome" component={HomeScreen} options={{ title: 'Profile' }} />
<Stack.Screen name="OidcLogin" component={OidcLoginScreen} options={{ title: 'Sign In' }} />
<Stack.Screen name="OidcHome" component={OidcHomeScreen} options={{ title: 'Profile' }} />
</Stack.Navigator>
</NavigationContainer>
</OidcProvider>
</JourneyProvider>
);
}
Screens navigate via useNavigation<NativeStackNavigationProp<RootStackParamList>>(). After successful login call navigation.replace('Home') (or 'JourneyHome'/'OidcHome'). After logout call navigation.replace('Login'). Use replace — not navigate — so the back button cannot return to the auth screen after login or to the home screen after logout.
All screens use useJourney() / useOidc() with no client argument — they read from the provider above the navigator.
Run the Ping SDK and navigation install command using the Bash tool:
# Journey — Basic tier (rn-core is a required peer dep)
cd <projectDir> && npm install @ping-identity/rn-core@1.0.0 @ping-identity/rn-journey@1.0.0 @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context
# Journey — Standard tier (adds FIDO, binding, device profile)
cd <projectDir> && npm install @ping-identity/rn-core@1.0.0 @ping-identity/rn-journey@1.0.0 @ping-identity/rn-fido@1.0.0 @ping-identity/rn-binding@1.0.0 @ping-identity/rn-device-profile@1.0.0 @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context
# Journey — Full tier (adds external IdP, logger, storage, device-id, oath, device-client on top of Standard)
cd <projectDir> && npm install @ping-identity/rn-core@1.0.0 @ping-identity/rn-journey@1.0.0 @ping-identity/rn-fido@1.0.0 @ping-identity/rn-binding@1.0.0 @ping-identity/rn-device-profile@1.0.0 @ping-identity/rn-external-idp@1.0.0 @ping-identity/rn-logger@1.0.0 @ping-identity/rn-storage@1.0.0 @ping-identity/rn-device-id@1.0.0 @ping-identity/rn-oath@1.0.0 @ping-identity/rn-device-client@1.0.0 @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context
# OIDC flow
cd <projectDir> && npm install @ping-identity/rn-core@1.0.0 @ping-identity/rn-oidc@1.0.0 @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context
The Ping SDK requires React Native >= 0.80.1. Apply these platform minimums before running pod install / gradle:
iOS — requires iOS 16.0. In ios/Podfile ensure:
platform :ios, '16.0'
Android — requires minSdk 29. In android/build.gradle ensure:
minSdkVersion = 29
Android (OIDC flow only) — rn-oidc injects ${appRedirectUriScheme} into its AndroidManifest.xml. Add a placeholder in android/app/build.gradle inside defaultConfig:
manifestPlaceholders = [appRedirectUriScheme: "<redirectUri-scheme>"]
where <redirectUri-scheme> is the scheme portion of your redirectUri (e.g. com.example.app for com.example.app://oauth2redirect). Without this the build fails with "no value for <appRedirectUriScheme> is provided".
iOS (OIDC flow only) — register the redirect URI scheme in ios/<AppName>/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string><redirectUri-scheme></string>
</array>
</dict>
</array>
Android (rn-device-profile only) — the network collector requires ACCESS_NETWORK_STATE. Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Optional: add ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATION if using the location collector.
Then run pod install:
cd <projectDir>/ios && pod install
Ask the user which platform(s) to launch using AskUserQuestion:
"Launch the app now?"
Options:
A) iOS — run on booted iOS simulator
B) Android — run on booted Android emulator / connected device
C) Both — launch iOS and Android
D) Skip — I'll run it manually
For each selected platform, start Metro in the background first (if not already running), then run the app:
iOS:
# Start Metro in background
cd <projectDir> && npx react-native start --reset-cache &
# Wait ~5s for Metro to be ready, then build and install
cd <projectDir> && npx react-native run-ios --no-packager
Android (requires a booted emulator or connected device — check with adb devices first):
cd <projectDir> && npx react-native run-android --no-packager
After launching, take a simulator/emulator screenshot and show it to the user to confirm the app is running. The expected first screen is either a loading spinner (Journey starting) or an error view with "Try again" (placeholder server URL — correct behaviour).
Report what was scaffolded with a summary of next steps (fill in placeholders, register redirect URI scheme in AndroidManifest.xml and Info.plist).
If intent is B (Add to existing app) or outputDir is null:
Write files to outputDir using the Write tool when outputDir is set; otherwise print inline. Do not run npx react-native init or any scaffold command.
Run the install command for the chosen flow and tier using the Bash tool (same commands as intent A step 5, but cd to outputDir instead of a new scaffold directory). If outputDir is null, print the install command for the user to run.
For OIDC or Journey+OIDC flows, remind the user to add the redirect URI scheme native wiring (Android manifestPlaceholders + intent filter, iOS CFBundleURLTypes) as documented in the platform setup section above.
Ask the user which platform(s) to launch (same options as intent A step 6: iOS / Android / Both / Skip).
For each selected platform, run the app using the same commands as intent A step 7. If outputDir is null, print the run commands instead.
Report what was generated with a summary of remaining next steps.
Parameters (with-args invocation)
| Parameter |
Syntax |
Purpose |
create-sample |
create-sample "<description>" |
Generate a complete runnable sample for the described flow |
flow |
flow journey, flow oidc, or flow both |
Set the flow type explicitly |
app-name |
app-name "<name>" |
Set the app name. Defaults to "PingDemo" if omitted. |
create-sample "<description>"
Analyse the description — identify flow type (journey or oidc).
Ask one clarifying question only if the flow type is genuinely ambiguous. Otherwise collect required parameters for the detected flow (see W3 table) in a single AskUserQuestion with an explicit "I can use placeholders" option.
Resolve the app name from app-name or use "PingDemo".
Generate — produce the following files inline (or to disk if an output path is given), substituting all placeholder values:
Journey flow:
<AppName>JourneyClient.ts — createJourneyClient singleton
<AppName>LoginScreen.tsx — useJourney screen with node switch
CallbackRenderer.tsx — node.callbacks renderer for the detected callback set
HomeScreen.tsx — authenticated screen showing userinfo
OIDC Web flow:
<AppName>OidcClient.ts — createOidcClient + createOidcWebClient singletons
<AppName>LoginScreen.tsx — useOidc screen with restore() on mount and authorize() on press
HomeScreen.tsx — authenticated screen with token display and sign-out
Print each file with a // --- <Filename> --- header. Include package.json dependency snippets and native wiring notes (redirect URI for both platforms).
Examples:
/ping-orchestration-react-native-sdk create-sample "username and password login using Journey"
/ping-orchestration-react-native-sdk create-sample "OIDC browser login with sign-out" app-name "MyApp"
/ping-orchestration-react-native-sdk create-sample "Journey login with FIDO passkey registration" app-name "FidoDemo"
/ping-orchestration-react-native-sdk flow journey
/ping-orchestration-react-native-sdk flow oidc
UnsupportedCallbackView
UnsupportedCallbackView is the standard fallback for any callback with executionMode === 'integration_required' or 'unsupported' that the app does not yet handle (e.g. PingOneProtectInitializeCallback, ReCaptchaEnterpriseCallback). All form-managed CallbackRenderer variants generate it automatically. Manual-mode renderers should also include it as the default branch in their callback switch.
Reference Files
- references/integration-guide.md — Full integration guide: installation, Journey, OIDC, FIDO, Push, common pitfalls
- references/journey-client.md — Full
createJourneyClient config, JourneyConfig, all hook actions, JourneyNextInput
- references/callbacks.md — All callback types,
useJourneyForm conjunction pattern and when to use it, execution modes
- references/oidc-client.md — Full
OidcClientConfig, createOidcWebClient, all useOidc actions, error codes
- references/common-mistakes.md — RN-specific gotchas: client scope, navigation, callback index, OIDC redirect, platform minimums
- references/oath.md —
createOathClient, TOTP/HOTP credential management, policy evaluator, error codes
- references/journey-export-analysis.md — Journey export JSON analysis steps (A1–A8), node→callback mapping table
1---2name: ping-orchestration-react-native-sdk3description: Guide for building React Native apps that integrate with the Ping Identity React Native SDK (npm scope: `@ping-identity`; packages: `@ping-identity/rn-journey`, `@ping-identity/rn-oidc`, `@ping-identity/rn-fido`, `@ping-identity/rn-push`, `@ping-identity/rn-oath`, `@ping-identity/rn-binding`, `@ping-identity/rn-device-client`, `@ping-identity/rn-device-profile`, `@ping-identity/rn-external-idp`, `@ping-identity/rn-core`). Use this skill whenever the user is: (1) building any React Native app that authenticates against PingOne, PingOne Advanced Identity Cloud (AIC), or PingAM using Journey or OIDC flows; (2) rendering Journey callbacks (NameCallback, PasswordCallback, FIDO, DeviceBinding, etc.) in React Native components; (3) configuring `createJourneyClient` or `createOidcClient`; (4) using `useJourney`, `useJourneyForm`, `JourneyProvider`, `useOidc`, or `OidcProvider`; (5) handling node types (ContinueNode, SuccessNode, FailureNode, ErrorNode); (6) wiring OIDC browser redirect URIs for iOS and Android; (7) a4license: MIT5---67## Skill Parameters89When invoked with no arguments, run the wizard. With arguments, generate inline.1011### No-arg Invocation — Wizard Mode1213**Step W1 — Determine intent** using `AskUserQuestion`:1415```16"What would you like to do?"17Options:18 A) Scaffold a new React Native project — complete working app with Ping SDK wired in19 B) Add to an existing app — generate only the files to drop into your project20 C) Browse the reference guide — show the full integration guide21 D) Something else — let me describe what I need22```2324- **A/B** → Step W1b25- **C** → read and display [references/integration-guide.md](references/integration-guide.md). Stop.26- **D** → follow-up free-text question, route accordingly.2728**Step W1b — Journey export offer** (options A and B only).2930Ask: "Do you have a Journey export JSON? If so, paste it and I'll analyse it to identify the exact callbacks your Journey uses and pre-populate the callback tier."3132- If provided: run Section 7 (Journey Export Analysis, [references/journey-export-analysis.md](references/journey-export-analysis.md)) before Step W2. Pre-populate `journeyName` and `callbackTier` from the analysis. Ask Step W2.5 (callback mode) as usual — `callbackMode` cannot be inferred from the export and must still be asked.33- If not provided: continue to Step W2 as normal.3435**Step W2 — Flow type** using `AskUserQuestion`:3637```38"Which authentication flow do you need?"39Options:40 1) Journey — native in-app UI, targets PingAM / PingOne AIC41 2) OIDC Web — browser-based login, any OIDC provider42 3) Journey + OIDC — both flows in one app, FlowPicker as the entry screen43```4445- **1** → store `flowType = 'journey'`46- **2** → store `flowType = 'oidc'`47- **3** → store `flowType = 'both'`; collect parameters for both Journey and OIDC in W3; ask W2.5 and W2.6 as normal for the Journey portion; generate both sets of screens plus `FlowPicker`; install combined package set (Journey full tier + `rn-oidc`)4849**Step W2.5 — Callback handling** (Journey only, skip when `flowType = 'oidc'`) using `AskUserQuestion`:5051```52"How would you like to handle Journey callbacks?"53Options:54 A) Managed (Recommended) — useJourneyForm handles field state, validation,55 and payload building. Simpler code; less boilerplate.56 B) Manual — useJourney only. You control field state and57 build the submit payload yourself. More flexibility, more code.58```5960Store the answer as `callbackMode` (`managed` or `manual`). Used in step 4 to pick the correct `CallbackRenderer` template.6162**Step W2.6 — Callback tier** (Journey only) using `AskUserQuestion`:6364```65"Which callbacks does your Journey use?"66Options:67 A) Basic — username, password, text, choice, T&C, KBA.68 No extra packages needed beyond rn-journey.69 B) Standard — Basic + FIDO passkeys, device binding, device profile.70 Adds: rn-fido, rn-binding, rn-device-profile.71 C) Full — Standard + social / external IdP (Google, Apple, Facebook).72 Adds: rn-external-idp.73```7475Store the answer as `callbackTier` (`basic`, `standard`, or `full`). Used in steps 4 and 5 to pick the correct templates and install commands.7677**Step W3 — Collect configuration.**7879Ask all required parameters in a single `AskUserQuestion`. Show defaults where they exist. Do not generate until every required field has a value.8081**Common parameters (both flows):**8283| Parameter | Required | Default | Description |84|---|---|---|---|85| `appName` | Scaffold only | `PingDemo` | App name. **Only ask when intent is A (scaffold)**. For intent B (add to existing), skip this — use `PingDemo` as default and never prompt for it. |86| `clientId` | Yes | — | OAuth 2.0 Client ID |87| `redirectUri` | Yes | — | OAuth 2.0 redirect URI (custom scheme, e.g. `com.example.app://callback`) |88| `discoveryEndpoint` | Yes | — | Full `.well-known/openid-configuration` URL |89| `scopes` | No | `openid profile email` | Space-separated OAuth 2.0 scopes |9091**Journey-only additional parameters:**9293| Parameter | Required | Default | Description |94|---|---|---|---|95| `serverUrl` | Yes | — | PingAM/AIC base URL, no trailing `/` |96| `realm` | No | `alpha` | Authentication realm |97| `cookieName` | No | `iPlanetDirectoryPro` | Session cookie name |98| `journeyName` | No | `Login` | Journey tree name |99100**Validation rules:**101- `redirectUri` must use a custom scheme (not `http://` or `https://`).102- `discoveryEndpoint` must start with `https://` and end with `/.well-known/openid-configuration`.103- `scopes` must include `openid`. If missing, prepend it and warn.104- `serverUrl` (Journey) must start with `https://` and have no trailing `/`.105106**Step W3.5 — Output path.** Ask where to write the files using `AskUserQuestion`:107108```109"Where should the files be written?"110Options:111 A) Current working directory — write files to the project root112 B) Specify a path — I'll provide an absolute or relative path113 C) Print to chat only — show the code inline, don't write to disk114```115116- **A** → use the current working directory as `outputDir`.117- **B** → follow-up free-text question: "Enter the output directory path:". Use that value as `outputDir`.118- **C** → set `outputDir = null` (inline output only).119120> **Scaffold intent note:** When intent is **A (Scaffold a new project)** and `outputDir` is set, the React Native project will be initialised as `<outputDir>/<appName>/`. All Ping SDK files are written into that subdirectory. The final structure is `<outputDir>/<appName>/` containing the generated project.121122**Step W4 — Confirm and generate.** Summarise collected values (including output path) in a short table, ask "Ready to generate — does this look right?", then proceed on confirmation.123124**If intent is A (Scaffold a new project) and `outputDir` is set:**1251261. Run the React Native scaffold command first using the Bash tool:127 ```bash128 npx @react-native-community/cli@latest init <AppName> --directory <outputDir>/<AppName>129 ```130 Wait for it to complete before writing any files. If it fails, report the error and stop.1311322. Set `projectDir = <outputDir>/<AppName>`.1331343. **Apply Ping Identity branding and copy templates** — always do this before writing any screen files.135136 - Read `assets/PingTheme.tsx.template` from this skill and write it to `<projectDir>/src/theme/PingTheme.tsx` (no substitutions needed).137 - Copy `assets/ping_logo.png` from this skill to `<projectDir>/src/assets/ping_logo.png`.138 - Create the directory `<projectDir>/src/callbacks/`.139140 All generated screens import branded components from `../theme/PingTheme` — never inline ad-hoc styles.141142 Branded components available: `PingPrimaryButton`, `PingHeaderView`, `PingTextField`, `PingSecureField`, `PingErrorMessage`, `PingErrorCard`, `PingLoadingOverlay`. Color tokens: `PingColors.red`, `PingColors.redDark`, `PingColors.textField`, etc.1431444. **Write screens and callbacks from templates** — read each template from this skill's `assets/` directory and write it to the project. Do not generate these files from memory; always read the template first.145146 **Callback components — Basic tier** (all tiers write these):147 - `assets/callbacks/NameCallbackView.tsx.template` → `src/callbacks/NameCallbackView.tsx`148 - `assets/callbacks/ValidatedUsernameCallbackView.tsx.template` → `src/callbacks/ValidatedUsernameCallbackView.tsx`149 - `assets/callbacks/PasswordCallbackView.tsx.template` → `src/callbacks/PasswordCallbackView.tsx`150 - `assets/callbacks/ValidatedPasswordCallbackView.tsx.template` → `src/callbacks/ValidatedPasswordCallbackView.tsx`151 - `assets/callbacks/TextInputCallbackView.tsx.template` → `src/callbacks/TextInputCallbackView.tsx`152 - `assets/callbacks/StringAttributeInputCallbackView.tsx.template` → `src/callbacks/StringAttributeInputCallbackView.tsx`153 - `assets/callbacks/NumberAttributeInputCallbackView.tsx.template` → `src/callbacks/NumberAttributeInputCallbackView.tsx`154 - `assets/callbacks/BooleanAttributeInputCallbackView.tsx.template` → `src/callbacks/BooleanAttributeInputCallbackView.tsx`155 - `assets/callbacks/TextOutputCallbackView.tsx.template` → `src/callbacks/TextOutputCallbackView.tsx`156 - `assets/callbacks/SuspendedTextOutputCallbackView.tsx.template` → `src/callbacks/SuspendedTextOutputCallbackView.tsx`157 - `assets/callbacks/ChoiceCallbackView.tsx.template` → `src/callbacks/ChoiceCallbackView.tsx`158 - `assets/callbacks/ConfirmationCallbackView.tsx.template` → `src/callbacks/ConfirmationCallbackView.tsx`159 - `assets/callbacks/TermsAndConditionsCallbackView.tsx.template` → `src/callbacks/TermsAndConditionsCallbackView.tsx`160 - `assets/callbacks/KbaCreateCallbackView.tsx.template` → `src/callbacks/KbaCreateCallbackView.tsx`161 - `assets/callbacks/PollingWaitCallbackView.tsx.template` → `src/callbacks/PollingWaitCallbackView.tsx`162 - `assets/callbacks/UnsupportedCallbackView.tsx.template` → `src/callbacks/UnsupportedCallbackView.tsx`163164 **Callback components — Standard tier** (write these when `callbackTier = standard` or `full`):165 - `assets/callbacks/ConsentMappingCallbackView.tsx.template` → `src/callbacks/ConsentMappingCallbackView.tsx`166 - `assets/callbacks/FidoRegistrationCallbackView.tsx.template` → `src/callbacks/FidoRegistrationCallbackView.tsx`167 - `assets/callbacks/FidoAuthenticationCallbackView.tsx.template` → `src/callbacks/FidoAuthenticationCallbackView.tsx`168 - `assets/callbacks/DeviceBindingCallbackView.tsx.template` → `src/callbacks/DeviceBindingCallbackView.tsx`169 - `assets/callbacks/DeviceSigningVerifierCallbackView.tsx.template` → `src/callbacks/DeviceSigningVerifierCallbackView.tsx`170 - `assets/callbacks/DeviceProfileCallbackView.tsx.template` → `src/callbacks/DeviceProfileCallbackView.tsx`171172 **Callback components — Full tier** (write these when `callbackTier = full`):173 - `assets/callbacks/SelectIdpCallbackView.tsx.template` → `src/callbacks/SelectIdpCallbackView.tsx`174175 **Screen files** (Journey flow) — pick template based on `callbackMode` + `callbackTier`:176177 | `callbackMode` | `callbackTier` | Template to use |178 |---|---|---|179 | managed | basic | `assets/CallbackRenderer.form.basic.tsx.template` |180 | managed | standard | `assets/CallbackRenderer.form.standard.tsx.template` |181 | managed | full | `assets/CallbackRenderer.form.tsx.template` |182 | manual | basic | `assets/CallbackRenderer.basic.tsx.template` |183 | manual | standard | `assets/CallbackRenderer.standard.tsx.template` |184 | manual | full | `assets/CallbackRenderer.tsx.template` |185186 Write the chosen template to `<projectDir>/src/screens/CallbackRenderer.tsx`.187188 - Read `assets/LoginScreen.tsx.template` → write to `<projectDir>/src/screens/LoginScreen.tsx`189 - Read `assets/HomeScreen.tsx.template` → write to `<projectDir>/src/screens/HomeScreen.tsx`190191 **Screen files** (OIDC flow):192 - Read `assets/LoginScreen.oidc.tsx.template` → write to `<projectDir>/src/screens/LoginScreen.tsx`193 - Read `assets/HomeScreen.oidc.tsx.template` → write to `<projectDir>/src/screens/HomeScreen.tsx`194195 After writing templates, substitute `<AppName>` placeholders in `LoginScreen.tsx` and `HomeScreen.tsx` with the actual app name.196197 **These files are still generated** (they contain user-supplied config values):198 - `<projectDir>/src/<AppName>JourneyClient.ts` (or `OidcClient.ts` for OIDC)199200 **Full tier only** — also export `idpClient` from the Journey client file:201 ```ts202 import { createExternalIdpClient } from '@ping-identity/rn-external-idp';203 export const idpClient = createExternalIdpClient();204 ```205 `SelectIdpCallbackView` imports `idpClient` from this file.2062075. Overwrite `<projectDir>/App.tsx` with a React Navigation stack. **All Ping providers must wrap the single `NavigationContainer`** — never use multiple `NavigationContainer` instances or nest providers inside screen components. A single flat stack gives every screen a back button automatically.208209 **Journey flow:**210 ```tsx211 import React from 'react';212 import { NavigationContainer, useNavigation } from '@react-navigation/native';213 import { createNativeStackNavigator } from '@react-navigation/native-stack';214 import type { NativeStackNavigationProp } from '@react-navigation/native-stack';215 import { JourneyProvider } from '@ping-identity/rn-journey';216 import journeyClient from './<AppName>JourneyClient';217 import LoginScreen from './screens/LoginScreen';218 import HomeScreen from './screens/HomeScreen';219220 export type RootStackParamList = {221 Login: undefined;222 Home: undefined;223 };224225 const Stack = createNativeStackNavigator<RootStackParamList>();226227 export default function App() {228 return (229 <JourneyProvider client={journeyClient}>230 <NavigationContainer>231 <Stack.Navigator initialRouteName="Login">232 <Stack.Screen name="Login" component={LoginScreen} options={{ headerShown: false }} />233 <Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Profile' }} />234 </Stack.Navigator>235 </NavigationContainer>236 </JourneyProvider>237 );238 }239 ```240241 **OIDC flow:**242 ```tsx243 import React, { useMemo } from 'react';244 import { NavigationContainer } from '@react-navigation/native';245 import { createNativeStackNavigator } from '@react-navigation/native-stack';246 import { OidcProvider, createOidcClient, createOidcWebClient } from '@ping-identity/rn-oidc';247 import LoginScreen from './screens/LoginScreen';248 import HomeScreen from './screens/HomeScreen';249250 export type RootStackParamList = {251 Login: undefined;252 Home: undefined;253 };254255 const Stack = createNativeStackNavigator<RootStackParamList>();256257 export default function App() {258 const client = useMemo(() => {259 const oidcClient = createOidcClient({260 clientId: '<clientId>',261 discoveryEndpoint: '<discoveryEndpoint>',262 redirectUri: '<redirectUri>',263 scopes: ['openid', 'profile', 'email'],264 });265 return createOidcWebClient(oidcClient);266 }, []);267268 return (269 <OidcProvider client={client}>270 <NavigationContainer>271 <Stack.Navigator initialRouteName="Login">272 <Stack.Screen name="Login" component={LoginScreen} options={{ headerShown: false }} />273 <Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Profile' }} />274 </Stack.Navigator>275 </NavigationContainer>276 </OidcProvider>277 );278 }279 ```280281 **Both flows (flow picker):** When scaffolding both Journey and OIDC, use a single stack with a `FlowPicker` screen as the initial route. Both providers sit above the single `NavigationContainer`. The `OidcProvider` client is created in `useMemo` at the `App` level — never inside a screen component.282283 ```tsx284 export type RootStackParamList = {285 FlowPicker: undefined;286 JourneyLogin: undefined;287 JourneyHome: undefined;288 OidcLogin: undefined;289 OidcHome: undefined;290 };291292 export default function App() {293 const oidcClient = useMemo(() => createOidcWebClient(createOidcClient({...})), []);294 return (295 <JourneyProvider client={journeyClient}>296 <OidcProvider client={oidcClient}>297 <NavigationContainer>298 <Stack.Navigator initialRouteName="FlowPicker">299 <Stack.Screen name="FlowPicker" component={FlowPicker} options={{ headerShown: false }} />300 <Stack.Screen name="JourneyLogin" component={LoginScreen} options={{ title: 'Sign In' }} />301 <Stack.Screen name="JourneyHome" component={HomeScreen} options={{ title: 'Profile' }} />302 <Stack.Screen name="OidcLogin" component={OidcLoginScreen} options={{ title: 'Sign In' }} />303 <Stack.Screen name="OidcHome" component={OidcHomeScreen} options={{ title: 'Profile' }} />304 </Stack.Navigator>305 </NavigationContainer>306 </OidcProvider>307 </JourneyProvider>308 );309 }310 ```311312 Screens navigate via `useNavigation<NativeStackNavigationProp<RootStackParamList>>()`. After successful login call `navigation.replace('Home')` (or `'JourneyHome'`/`'OidcHome'`). After logout call `navigation.replace('Login')`. Use `replace` — not `navigate` — so the back button cannot return to the auth screen after login or to the home screen after logout.313314 All screens use `useJourney()` / `useOidc()` with no client argument — they read from the provider above the navigator.3153165. Run the Ping SDK and navigation install command using the Bash tool:317 ```bash318 # Journey — Basic tier (rn-core is a required peer dep)319 cd <projectDir> && npm install @ping-identity/rn-core@1.0.0 @ping-identity/rn-journey@1.0.0 @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context320321 # Journey — Standard tier (adds FIDO, binding, device profile)322 cd <projectDir> && npm install @ping-identity/rn-core@1.0.0 @ping-identity/rn-journey@1.0.0 @ping-identity/rn-fido@1.0.0 @ping-identity/rn-binding@1.0.0 @ping-identity/rn-device-profile@1.0.0 @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context323324 # Journey — Full tier (adds external IdP, logger, storage, device-id, oath, device-client on top of Standard)325 cd <projectDir> && npm install @ping-identity/rn-core@1.0.0 @ping-identity/rn-journey@1.0.0 @ping-identity/rn-fido@1.0.0 @ping-identity/rn-binding@1.0.0 @ping-identity/rn-device-profile@1.0.0 @ping-identity/rn-external-idp@1.0.0 @ping-identity/rn-logger@1.0.0 @ping-identity/rn-storage@1.0.0 @ping-identity/rn-device-id@1.0.0 @ping-identity/rn-oath@1.0.0 @ping-identity/rn-device-client@1.0.0 @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context326327 # OIDC flow328 cd <projectDir> && npm install @ping-identity/rn-core@1.0.0 @ping-identity/rn-oidc@1.0.0 @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context329 ```330 The Ping SDK requires React Native >= 0.80.1. Apply these platform minimums before running pod install / gradle:331332 **iOS** — requires iOS 16.0. In `ios/Podfile` ensure:333 ```334 platform :ios, '16.0'335 ```336337 **Android** — requires minSdk 29. In `android/build.gradle` ensure:338 ```339 minSdkVersion = 29340 ```341 **Android (OIDC flow only)** — `rn-oidc` injects `${appRedirectUriScheme}` into its `AndroidManifest.xml`. Add a placeholder in `android/app/build.gradle` inside `defaultConfig`:342 ```groovy343 manifestPlaceholders = [appRedirectUriScheme: "<redirectUri-scheme>"]344 ```345 where `<redirectUri-scheme>` is the scheme portion of your `redirectUri` (e.g. `com.example.app` for `com.example.app://oauth2redirect`). Without this the build fails with "no value for <appRedirectUriScheme> is provided".346347 **iOS (OIDC flow only)** — register the redirect URI scheme in `ios/<AppName>/Info.plist`:348 ```xml349 <key>CFBundleURLTypes</key>350 <array>351 <dict>352 <key>CFBundleURLSchemes</key>353 <array>354 <string><redirectUri-scheme></string>355 </array>356 </dict>357 </array>358 ```359360 **Android (`rn-device-profile` only)** — the network collector requires `ACCESS_NETWORK_STATE`. Add to `android/app/src/main/AndroidManifest.xml`:361 ```xml362 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />363 ```364 Optional: add `ACCESS_FINE_LOCATION` / `ACCESS_COARSE_LOCATION` if using the location collector.365366 Then run `pod install`:367 ```bash368 cd <projectDir>/ios && pod install369 ```3703716. Ask the user which platform(s) to launch using `AskUserQuestion`:372 ```373 "Launch the app now?"374 Options:375 A) iOS — run on booted iOS simulator376 B) Android — run on booted Android emulator / connected device377 C) Both — launch iOS and Android378 D) Skip — I'll run it manually379 ```3803817. For each selected platform, start Metro in the background first (if not already running), then run the app:382383 **iOS:**384 ```bash385 # Start Metro in background386 cd <projectDir> && npx react-native start --reset-cache &387 # Wait ~5s for Metro to be ready, then build and install388 cd <projectDir> && npx react-native run-ios --no-packager389 ```390391 **Android** (requires a booted emulator or connected device — check with `adb devices` first):392 ```bash393 cd <projectDir> && npx react-native run-android --no-packager394 ```395396 After launching, take a simulator/emulator screenshot and show it to the user to confirm the app is running. The expected first screen is either a loading spinner (Journey starting) or an error view with "Try again" (placeholder server URL — correct behaviour).3973988. Report what was scaffolded with a summary of next steps (fill in placeholders, register redirect URI scheme in AndroidManifest.xml and Info.plist).399400**If intent is B (Add to existing app) or `outputDir` is null:**4014021. Write files to `outputDir` using the Write tool when `outputDir` is set; otherwise print inline. Do **not** run `npx react-native init` or any scaffold command.4034042. Run the install command for the chosen flow and tier using the Bash tool (same commands as intent A step 5, but `cd` to `outputDir` instead of a new scaffold directory). If `outputDir` is null, print the install command for the user to run.4054063. For OIDC or Journey+OIDC flows, remind the user to add the redirect URI scheme native wiring (Android `manifestPlaceholders` + intent filter, iOS `CFBundleURLTypes`) as documented in the platform setup section above.4074084. Ask the user which platform(s) to launch (same options as intent A step 6: iOS / Android / Both / Skip).4094105. For each selected platform, run the app using the same commands as intent A step 7. If `outputDir` is null, print the run commands instead.4114126. Report what was generated with a summary of remaining next steps.413414---415416### Parameters (with-args invocation)417418| Parameter | Syntax | Purpose |419|---|---|---|420| `create-sample` | `create-sample "<description>"` | Generate a complete runnable sample for the described flow |421| `flow` | `flow journey`, `flow oidc`, or `flow both` | Set the flow type explicitly |422| `app-name` | `app-name "<name>"` | Set the app name. Defaults to `"PingDemo"` if omitted. |423424### `create-sample "<description>"`4254261. **Analyse** the description — identify flow type (`journey` or `oidc`).4272. **Ask one clarifying question** only if the flow type is genuinely ambiguous. Otherwise collect required parameters for the detected flow (see W3 table) in a single `AskUserQuestion` with an explicit "I can use placeholders" option.4283. **Resolve the app name** from `app-name` or use `"PingDemo"`.4294. **Generate** — produce the following files inline (or to disk if an output path is given), substituting all placeholder values:430431 **Journey flow:**432 - `<AppName>JourneyClient.ts` — `createJourneyClient` singleton433 - `<AppName>LoginScreen.tsx` — `useJourney` screen with node switch434 - `CallbackRenderer.tsx` — `node.callbacks` renderer for the detected callback set435 - `HomeScreen.tsx` — authenticated screen showing userinfo436437 **OIDC Web flow:**438 - `<AppName>OidcClient.ts` — `createOidcClient` + `createOidcWebClient` singletons439 - `<AppName>LoginScreen.tsx` — `useOidc` screen with `restore()` on mount and `authorize()` on press440 - `HomeScreen.tsx` — authenticated screen with token display and sign-out4414425. **Print each file** with a `// --- <Filename> ---` header. Include `package.json` dependency snippets and native wiring notes (redirect URI for both platforms).443444**Examples:**445446```447/ping-orchestration-react-native-sdk create-sample "username and password login using Journey"448/ping-orchestration-react-native-sdk create-sample "OIDC browser login with sign-out" app-name "MyApp"449/ping-orchestration-react-native-sdk create-sample "Journey login with FIDO passkey registration" app-name "FidoDemo"450/ping-orchestration-react-native-sdk flow journey451/ping-orchestration-react-native-sdk flow oidc452```453454---455456## UnsupportedCallbackView457458`UnsupportedCallbackView` is the standard fallback for any callback with `executionMode === 'integration_required'` or `'unsupported'` that the app does not yet handle (e.g. `PingOneProtectInitializeCallback`, `ReCaptchaEnterpriseCallback`). All form-managed `CallbackRenderer` variants generate it automatically. Manual-mode renderers should also include it as the `default` branch in their callback switch.459460## Reference Files461462- [references/integration-guide.md](references/integration-guide.md) — Full integration guide: installation, Journey, OIDC, FIDO, Push, common pitfalls463- [references/journey-client.md](references/journey-client.md) — Full `createJourneyClient` config, `JourneyConfig`, all hook actions, `JourneyNextInput`464- [references/callbacks.md](references/callbacks.md) — All callback types, `useJourneyForm` conjunction pattern and when to use it, execution modes465- [references/oidc-client.md](references/oidc-client.md) — Full `OidcClientConfig`, `createOidcWebClient`, all `useOidc` actions, error codes466- [references/common-mistakes.md](references/common-mistakes.md) — RN-specific gotchas: client scope, navigation, callback index, OIDC redirect, platform minimums467- [references/oath.md](references/oath.md) — `createOathClient`, TOTP/HOTP credential management, policy evaluator, error codes468- [references/journey-export-analysis.md](references/journey-export-analysis.md) — Journey export JSON analysis steps (A1–A8), node→callback mapping table