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
journeyNameandcallbackTierfrom the analysis. Ask Step W2.5 (callback mode) as usual —callbackModecannot 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 plusFlowPicker; 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:
redirectUrimust use a custom scheme (nothttp://orhttps://).discoveryEndpointmust start withhttps://and end with/.well-known/openid-configuration.scopesmust includeopenid. If missing, prepend it and warn.serverUrl(Journey) must start withhttps://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
outputDiris 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.templatefrom this skill and write it to<projectDir>/src/theme/PingTheme.tsx(no substitutions needed). - Copy
assets/ping_logo.pngfrom 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. - Read
-
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.tsxassets/callbacks/ValidatedUsernameCallbackView.tsx.template→src/callbacks/ValidatedUsernameCallbackView.tsxassets/callbacks/PasswordCallbackView.tsx.template→src/callbacks/PasswordCallbackView.tsxassets/callbacks/ValidatedPasswordCallbackView.tsx.template→src/callbacks/ValidatedPasswordCallbackView.tsxassets/callbacks/TextInputCallbackView.tsx.template→src/callbacks/TextInputCallbackView.tsxassets/callbacks/StringAttributeInputCallbackView.tsx.template→src/callbacks/StringAttributeInputCallbackView.tsxassets/callbacks/NumberAttributeInputCallbackView.tsx.template→src/callbacks/NumberAttributeInputCallbackView.tsxassets/callbacks/BooleanAttributeInputCallbackView.tsx.template→src/callbacks/BooleanAttributeInputCallbackView.tsxassets/callbacks/TextOutputCallbackView.tsx.template→src/callbacks/TextOutputCallbackView.tsxassets/callbacks/SuspendedTextOutputCallbackView.tsx.template→src/callbacks/SuspendedTextOutputCallbackView.tsxassets/callbacks/ChoiceCallbackView.tsx.template→src/callbacks/ChoiceCallbackView.tsxassets/callbacks/ConfirmationCallbackView.tsx.template→src/callbacks/ConfirmationCallbackView.tsxassets/callbacks/TermsAndConditionsCallbackView.tsx.template→src/callbacks/TermsAndConditionsCallbackView.tsxassets/callbacks/KbaCreateCallbackView.tsx.template→src/callbacks/KbaCreateCallbackView.tsxassets/callbacks/PollingWaitCallbackView.tsx.template→src/callbacks/PollingWaitCallbackView.tsxassets/callbacks/UnsupportedCallbackView.tsx.template→src/callbacks/UnsupportedCallbackView.tsx
Callback components — Standard tier (write these when
callbackTier = standardorfull):assets/callbacks/ConsentMappingCallbackView.tsx.template→src/callbacks/ConsentMappingCallbackView.tsxassets/callbacks/FidoRegistrationCallbackView.tsx.template→src/callbacks/FidoRegistrationCallbackView.tsxassets/callbacks/FidoAuthenticationCallbackView.tsx.template→src/callbacks/FidoAuthenticationCallbackView.tsxassets/callbacks/DeviceBindingCallbackView.tsx.template→src/callbacks/DeviceBindingCallbackView.tsxassets/callbacks/DeviceSigningVerifierCallbackView.tsx.template→src/callbacks/DeviceSigningVerifierCallbackView.tsxassets/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:callbackModecallbackTierTemplate to use managed basic assets/CallbackRenderer.form.basic.tsx.templatemanaged standard assets/CallbackRenderer.form.standard.tsx.templatemanaged full assets/CallbackRenderer.form.tsx.templatemanual basic assets/CallbackRenderer.basic.tsx.templatemanual standard assets/CallbackRenderer.standard.tsx.templatemanual full assets/CallbackRenderer.tsx.templateWrite 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 inLoginScreen.tsxandHomeScreen.tsxwith the actual app name.These files are still generated (they contain user-supplied config values):
<projectDir>/src/<AppName>JourneyClient.ts(orOidcClient.tsfor OIDC)
Full tier only — also export
idpClientfrom the Journey client file:import { createExternalIdpClient } from '@ping-identity/rn-external-idp'; export const idpClient = createExternalIdpClient();SelectIdpCallbackViewimportsidpClientfrom this file. -
Overwrite
<projectDir>/App.tsxwith a React Navigation stack. All Ping providers must wrap the singleNavigationContainer— never use multipleNavigationContainerinstances 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
FlowPickerscreen as the initial route. Both providers sit above the singleNavigationContainer. TheOidcProviderclient is created inuseMemoat theApplevel — 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 callnavigation.replace('Home')(or'JourneyHome'/'OidcHome'). After logout callnavigation.replace('Login'). Usereplace— notnavigate— 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-contextThe Ping SDK requires React Native >= 0.80.1. Apply these platform minimums before running pod install / gradle:
iOS — requires iOS 16.0. In
ios/Podfileensure:platform :ios, '16.0'Android — requires minSdk 29. In
android/build.gradleensure:minSdkVersion = 29Android (OIDC flow only) —
rn-oidcinjects${appRedirectUriScheme}into itsAndroidManifest.xml. Add a placeholder inandroid/app/build.gradleinsidedefaultConfig:manifestPlaceholders = [appRedirectUriScheme: "<redirectUri-scheme>"]where
<redirectUri-scheme>is the scheme portion of yourredirectUri(e.g.com.example.appforcom.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-profileonly) — the network collector requiresACCESS_NETWORK_STATE. Add toandroid/app/src/main/AndroidManifest.xml:<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />Optional: add
ACCESS_FINE_LOCATION/ACCESS_COARSE_LOCATIONif 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-packagerAndroid (requires a booted emulator or connected device — check with
adb devicesfirst):cd <projectDir> && npx react-native run-android --no-packagerAfter 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
outputDirusing the Write tool whenoutputDiris set; otherwise print inline. Do not runnpx react-native initor 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
cdtooutputDirinstead of a new scaffold directory). IfoutputDiris 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, iOSCFBundleURLTypes) 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
outputDiris 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 (
journeyoroidc). -
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
AskUserQuestionwith an explicit "I can use placeholders" option. -
Resolve the app name from
app-nameor 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—createJourneyClientsingleton<AppName>LoginScreen.tsx—useJourneyscreen with node switchCallbackRenderer.tsx—node.callbacksrenderer for the detected callback setHomeScreen.tsx— authenticated screen showing userinfo
OIDC Web flow:
<AppName>OidcClient.ts—createOidcClient+createOidcWebClientsingletons<AppName>LoginScreen.tsx—useOidcscreen withrestore()on mount andauthorize()on pressHomeScreen.tsx— authenticated screen with token display and sign-out
-
Print each file with a
// --- <Filename> ---header. Includepackage.jsondependency 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
createJourneyClientconfig,JourneyConfig, all hook actions,JourneyNextInput - references/callbacks.md — All callback types,
useJourneyFormconjunction pattern and when to use it, execution modes - references/oidc-client.md — Full
OidcClientConfig,createOidcWebClient, alluseOidcactions, 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