Use when building iOS authentication with PingOne DaVinci — scaffolds a complete SwiftUI + MVVM authentication flow using the Ping Orchestration iOS SDK’s DaVinci module against PingOne DaVinci. Handles DaVinci configuration, OIDC token exchange, dynamic collector rendering, device registration/authentication, FIDO2/passkeys, social login, PingOne Protect, and logout.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ping-orchestration-sdks:ping-orchestration-ios-davinci-sdkThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Scaffold a complete authentication flow in an iOS app using SwiftUI, MVVM, and the Ping Orchestration iOS SDK’s DaVinci module.
assets/CheckBoxView.swift.templateassets/ComboBoxView.swift.templateassets/ContinueNodeView.swift.templateassets/DavinciView.swift.templateassets/DavinciViewModel.swift.templateassets/DeviceAuthenticationView.swift.templateassets/DeviceRegistrationView.swift.templateassets/DropdownView.swift.templateassets/FidoAuthenticationView.swift.templateassets/FidoRegistrationView.swift.templateassets/FlowButtonView.swift.templateassets/LabelView.swift.templateassets/PasswordView.swift.templateassets/PhoneNumberView.swift.templateassets/PingProtectView.swift.templateassets/RadioButtonView.swift.templateassets/SocialButtonView.swift.templateassets/SubmitButtonView.swift.templateassets/TextView.swift.templateassets/ValidationViewModel.swift.templateScaffold a complete authentication flow in an iOS app using SwiftUI, MVVM, and the Ping Orchestration iOS SDK’s DaVinci module.
| Field | Value |
|---|---|
| Language | Swift |
| Framework | SwiftUI, Combine |
| SDK | Ping Identity Orchestration iOS SDK (PingDavinci, PingOidc, PingOrchestrate) |
| Pattern | MVVM (Model-View-ViewModel) with @StateObject / @ObservedObject |
| Min iOS | 16.0 |
| Xcode | Latest recommended |
This skill adds a complete authentication flow to an iOS application using SwiftUI and the MVVM pattern. It uses the DaVinci module of the Ping Orchestration iOS SDK to authenticate users against PingOne DaVinci.
DaVinci vs Journey: DaVinci uses PingOne as the orchestration server (not PingAM/AIC). It uses Collectors instead of Callbacks, and a
DaVinciclass instead ofJourney. The concepts are similar but the API surface is different.
The implementation covers:
@Published properties and @MainActorValidatedCollector protocol and ValidationViewModelContinueNode, SuccessNode, FailureNode, ErrorNodecontinueNode() to re-render previous formPackage.swift dependencies, Info.plist entries, and all views/components.Add the Ping iOS SDK via Swift Package Manager in Xcode:
Package URL: https://github.com/ForgeRock/ping-ios-sdk
Required products:
// In Package.swift or Xcode > File > Add Package Dependencies
.package(url: "https://github.com/ForgeRock/ping-ios-sdk", from: "1.3.0")
// Products to include:
// - PingDavinci (core DaVinci orchestration)
// - PingOidc (OIDC token management)
// - PingOrchestrate (base orchestration framework)
Optional products for advanced features:
// - PingExternalIdP (External IdP base)
// - PingExternalIdPGoogle (Google Sign-In)
// - PingExternalIdPFacebook (Facebook Login)
// - PingExternalIdPApple (Sign in with Apple)
// - PingProtect (PingOne Protect threat signals)
// - PingFido (FIDO2 / Passkey registration & authentication)
// - PingBrowser (Browser-based authentication flows)
Register a custom URL scheme for the OAuth 2.0 redirect:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Agent instruction: Before generating any file, collect the values below from the user. Ask for all
requiredparameters up front in a single prompt. For optional parameters, show the default and ask whether the user wants to override it. Do not proceed to Step 1 until every required parameter has a non-empty value.
| Parameter | Required | Default | Description |
|---|---|---|---|
clientId | Yes | — | OAuth 2.0 Client ID registered in PingOne for this iOS app |
discoveryEndpoint | Yes | — | Full OIDC discovery endpoint URL (.well-known/openid-configuration) from PingOne |
scopes | Yes | openid email profile | Space-separated OAuth 2.0 scopes to request |
redirectUri | Yes | myapp://callback | OAuth 2.0 redirect URI registered in PingOne |
Before I generate the files, I need a few details about your PingOne DaVinci setup:
1. Client ID — What is the OAuth 2.0 Client ID for this iOS app?
(From your PingOne OIDC Web App configuration)
2. Discovery Endpoint — What is the full OIDC discovery endpoint URL?
e.g. https://auth.pingone.com/<envId>/as/.well-known/openid-configuration
3. Scopes — Which OAuth 2.0 scopes? (default: openid email profile)
4. Redirect URI — What is the redirect URI? (default: myapp://callback)
discoveryEndpoint must end with /.well-known/openid-configuration.clientId must be non-empty.redirectUri must follow <scheme>://<path> format; the scheme must match Info.plist URL scheme.scopes does not include openid, prepend it automatically and warn the user.Create DavinciViewModel.swift. See DavinciViewModel.swift template.
Agent instruction: Substitute all
<parameter>placeholders with values collected above.
let davinci = DaVinci.createDaVinci { config in
config.module(OidcModule.config) { oidcValue in
oidcValue.clientId = "<clientId>"
oidcValue.scopes = ["openid", "profile", "email"]
oidcValue.redirectUri = "<redirectUri>"
oidcValue.discoveryEndpoint = "<discoveryEndpoint>"
}
}
See DaVinci SDK API Reference for all configuration options.
Create ValidationViewModel.swift. See ValidationViewModel.swift template.
The ValidationViewModel is shared across collector views via @EnvironmentObject to coordinate form validation before submission.
Create DavinciView.swift. See DavinciView.swift template.
struct DavinciView: View {
@ObservedObject var viewModel: DavinciViewModel
var body: some View {
switch viewModel.state.node {
case is ContinueNode:
ConnectorView(node: viewModel.state.node as! ContinueNode, ...)
case is SuccessNode:
// Navigate to authenticated state
case is ErrorNode:
// Show error with optional re-render of previous form
case is FailureNode:
// Show failure message
default:
ProgressView()
}
}
}
Create ContinueNodeView.swift which dispatches each collector to its dedicated SwiftUI view. See ContinueNodeView.swift template.
The pattern:
ForEach(node.collectors, id: \.id) { collector in
switch collector {
case let c as TextCollector: TextView(collector: c)
case let c as PasswordCollector: PasswordView(collector: c)
case let c as SubmitCollector: SubmitButtonView(collector: c, onNext: onNext)
case let c as FlowCollector: FlowButtonView(collector: c, onNext: onNext)
case let c as LabelCollector: LabelView(collector: c)
// ... more collectors
default: EmptyView()
}
}
See Collector Types Reference for the full list of supported collectors.
Create individual SwiftUI view files for each collector type. See the assets/ directory for all templates.
All collector types supported by the Ping Orchestration iOS SDK’s DaVinci module:
Core Collectors (PingDavinci module):
| Collector Class | SwiftUI View | Description |
|---|---|---|
TextCollector | TextView | Text input with validation |
PasswordCollector | PasswordView | Secure password input |
SubmitCollector | SubmitButtonView | Form submission button (Submittable) |
FlowCollector | FlowButtonView | Navigation between flow branches (Submittable) |
LabelCollector | LabelView | Static text/label display |
SingleSelectCollector | DropdownView / RadioButtonView | Single selection — Dropdown or Radio |
MultiSelectCollector | ComboBoxView / CheckBoxView | Multiple selection — ComboBox or Checkboxes |
PhoneNumberCollector | PhoneNumberView | Phone number input |
DeviceRegistrationCollector | DeviceRegistrationView | MFA device registration (Submittable) |
DeviceAuthenticationCollector | DeviceAuthenticationView | MFA device authentication (Submittable) |
Optional Collectors (additional modules):
| Collector Class | Module | SwiftUI View | Description |
|---|---|---|---|
IdpCollector | PingExternalIdP | SocialButtonView | Social login (Google, Facebook, Apple) |
FidoRegistrationCollector | PingFido | FidoRegistrationView | FIDO2 passkey / security-key registration (Submittable) |
FidoAuthenticationCollector | PingFido | FidoAuthenticationView | FIDO2 passkey / security-key authentication (Submittable) |
ProtectCollector | PingProtect | PingProtectView | PingOne Protect risk signals collection |
Each collector view follows this pattern:
collector.label)collector.value)onNext(true/false) as appropriate — true for submit actions, false for flow navigationNote: The
onNextclosure takes aBoolparameter:trueindicates a submit action (triggers validation),falseindicates flow navigation (skips validation).
@main
struct MyApp: App {
@StateObject var viewModel = DavinciViewModel()
var body: some Scene {
WindowGroup {
DavinciView(viewModel: viewModel)
}
}
}
For quick setup, use the scaffolding script to copy all template files into your project:
chmod +x scripts/scaffold_auth.sh
./scripts/scaffold_auth.sh \
--target-dir MyApp/Sources
See scaffold_auth.sh for details.
| Mistake | Fix |
|---|---|
| Wrong URL scheme | Must match Info.plist CFBundleURLSchemes |
Missing openid scope | Always include openid — required for OIDC token exchange |
| Unhandled collector type | Add a case in ContinueNodeView for every collector your DaVinci flow uses |
| Using Journey instead of DaVinci | DaVinci uses DaVinci.createDaVinci { } not Journey.createJourney { }, uses collectors not callbacks, uses PingDavinci not PingJourney |
| Not hiding default Next when Submittable present | When FlowCollector, SubmitCollector, DeviceRegistrationCollector, DeviceAuthenticationCollector, FidoRegistrationCollector, or FidoAuthenticationCollector is present, hide the fallback Next button |
Forgetting @EnvironmentObject for ValidationViewModel | ValidationViewModel must be injected via .environmentObject() on the parent view |
Calling node.next() without populating collectors | Always set collector values before advancing |
| Confusing DaVinci OidcModule with Journey OidcModule | Import PingDavinci, not PingJourney |
| Not handling ErrorNode's continueNode() | ErrorNode may expose continueNode() to re-render the previous form with an error overlay |
ping-quickstart — Platform detection and Ping Identity orientationping-orchestration-ios-journey-sdk — iOS authentication using the Journey module (for PingOne AIC/PingAM)npx claudepluginhub pingidentity/ping-sdk-agent-skills --plugin ping-orchestration-sdksCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.