Ping SDKs

DaVinci client sample apps

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

We provide the source code for sample applications that demonstrate how to integrate DaVinci flows into your mobile and web applications using the DaVinci client.

You can clone or download the sample source code from our GitHub repository at https://github.com/ForgeRock/sdk-sample-apps.

Each sample is a functional application designed to provide a practical guide for common integration scenarios. You can use them as a reference to understand key concepts or as a starting point for your own custom implementation.

The sample applications are provided "as is" for demonstration purposes only.

They are not official products of Ping Identity and are not officially supported.

We provide DaVinci client sample apps for the following platforms:

Android sample apps

kotlin-davinci

What does the kotlin-davinci sample support?
Feature Supported by sample

Orchestration

  • PingOne - DaVinci flows

Implementation

  • Embedded

Language

  • Kotlin

DaVinci Fields

  • Text

  • Password

  • Checkbox

  • Combobox

  • Dropdown

  • Label

  • Phone number

DaVinci Buttons

  • Flow button

  • Submit

  • Social sign-on

  • Radio

DaVinci Toolbox

  • OTP device registration

  • OTP device authentication

The kotlin-davinci application is a lightweight Android client.

Screenshot of the `kotlin-davinci` sample app on Android.

It is designed to demonstrate a core capability of the DaVinci client for Android: rendering a dynamic user interface based on signals received from a DaVinci flow.

Instead of having a hardcoded login screen, the app starts a DaVinci flow and waits for the server to send instructions on what to display. It then constructs the UI on-the-fly, whether it’s a username/password form, a message, or other interactive elements defined in your DaVinci flow.

The application’s code showcases several important implementation patterns for integrating with DaVinci:

1. Dynamic UI Rendering with Jetpack Compose

The app uses modern Android development practices, leveraging Jetpack Compose to build its user interface. The core logic resides in the DaVinciScreen.kt file.

  • It observes a state object from the DaVinciViewModel.

  • It uses a when statement to react to the current state of the DaVinci flow (Login, Success, or Failure).

  • For the Login state, it iterates through the list of collectors returned from the DaVinci flow and renders the appropriate Composable for each one.

    This is the dynamic part—if you change the DaVinci flow the UI will change without needing to recompile the app.

2. State Management with ViewModel and StateFlow

The application follows the recommended Android architecture by separating UI logic from business logic.

  • DaVinciViewModel.kt is responsible for all interactions with the Ping Identity SDK.

  • It uses a MutableStateFlow to hold the current state of the DaVinci flow (DaVinciAction). The UI (Composable functions) subscribes to this flow and automatically updates whenever the state changes.

    This decouples the SDK interaction from the UI, making the code cleaner and easier to test.

3. SDK Initialization and Configuration

The app demonstrates how to initialize and configure the SDK to connect to your specific PingOne and DaVinci environment. In DaVinciViewModel, it shows how to:

  • Provide the necessary DaVinci client configuration

  • Start the DaVinci flow by calling start().

4. Handling User Input

The sample shows how to collect data from the dynamically rendered input fields, such as username and password fields, package it into a Map, and submit it back to DaVinci using the action.next() method.

This is the mechanism for advancing the flow after a user provides their credentials or makes a choice.

iOS sample apps

swiftui-davinci

What does the swiftui-davinci sample support?
Feature Supported by sample

Orchestration

  • PingOne - DaVinci flows

Implementation

  • Embedded

Language

  • Swift

DaVinci Fields

  • Text

  • Password

  • Checkbox

  • Combobox

  • Dropdown

  • Label

DaVinci Buttons

  • Flow button

  • Submit

  • Social sign-on

  • Radio

The swiftui-davinci application is a modern iOS client built with Swift and SwiftUI.

Screenshot of the `swiftui-davinci` sample app on iOS.

It’s designed to demonstrate a core capability of the DaVinci client for iOS: rendering a dynamic user interface based on collectors received from a DaVinci flow.

Instead of having a hardcoded login screen, the app initiates a DaVinci flow and waits for the server to send collectors, which describe the required data. It then constructs the UI on-the-fly, whether it’s a username and password form, a message, or other interactive elements defined in your DaVinci flow.

The application’s code showcases several important implementation patterns for integrating with DaVinci using modern iOS development practices:

1. Dynamic UI Rendering with SwiftUI

The app uses SwiftUI to build its user interface declaratively. The core rendering logic resides in ContentView.swift.

  • It observes a state object from the DavinciViewModel.

  • It uses a switch statement to react to the current state of the DaVinci flow, either .loading, .loaded, or .success).

  • For the .loaded state, it iterates through an array of collectors returned by the DaVinci flow and renders the appropriate SwiftUI View for each one.

    This is the dynamic part—if you change the DaVinci flow on the server, the UI will change without needing to recompile the app.

2. State Management with Combine and ViewModel

The application follows the recommended MVVM (Model-View-ViewModel) architecture by separating UI logic from business logic.

  • DavinciViewModel.swift is responsible for interactions with the DaVinci client for iOS.

  • It uses @Published properties from the Combine framework to hold the current state of the DaVinci flow, such as flowState and inputs. The SwiftUI View subscribes to these properties and automatically updates whenever their values change.

    This decouples the SDK interaction from the UI, making the code cleaner and easier to manage.

3. SDK Initialization and Configuration

The app demonstrates how to initialize and configure the SDK to connect to your specific PingOne and DaVinci environment.

  • Provide the necessary DaVinci client configuration

  • Start the DaVinci flow by calling the start() method.

4. Handling User Input and Flow Progression

The sample shows how to collect data from the dynamically rendered input fields, bind it to a dictionary in the ViewModel, and submit it back to DaVinci.

This is the mechanism for advancing the flow after a user provides their credentials or makes a choice.

JavaScript sample apps

embedded-login-davinci

What does the embedded-login-davinci sample support?
Feature Supported by sample

Orchestration

  • PingOne - DaVinci flows

Implementation

  • Embedded

Language

  • TypeScript

DaVinci Fields

  • Text

  • Password

DaVinci Buttons

  • Flow button

  • Submit

  • Social sign-on

Integrations

  • PingOne Protect

The embedded-login-davinci application is a lightweight, single-page web application built with TypeScript and Vite.

davinci sample javascript login

Its primary purpose is to demonstrate how to embed a PingOne DaVinci authentication experience directly into a web page using the DaVinci client for JavaScript.

Instead of redirecting the user to a hosted login page, the application communicates with a DaVinci flow and dynamically builds the necessary UI components, such as username fields, password fields, and buttons in the browser based on the collectors it receives from DaVinci.

The application’s code showcases several important patterns for integrating DaVinci into a modern, framework-free web application:

1. Dynamic UI Rendering via DOM Manipulation

The core of the sample is its ability to render a UI without a front-end framework. The logic in src/main.ts is responsible for this.

  • It receives a response object from the DaVinci flow which contains an array of collectors.

  • It iterates through these collectors and uses a switch statement to identify the type of UI element to create, such as text, password, or button.

  • It then uses standard browser DOM APIs such as document.createElement, setAttribute, and appendChild to construct and display the corresponding HTML elements.

    This allows the UI to change dynamically based on the needs of the DaVinci flow.

2. SDK Initialization and Configuration

The application demonstrates how to configure and initialize the Ping Identity SDK to connect to a specific PingOne and DaVinci environment.

  • It uses Vite’s environment variable system to securely load configuration from a .env file. The configuration values such as VITE_WELLKNOWN_URL and VITE_WEB_OAUTH_CLIENT are accessed via import.meta.env.

  • In main.ts, it calls start() to begin the DaVinci flow.

3. Asynchronous Flow Management

The entire user interaction is managed as a series of asynchronous steps.

  • The application makes an initial call to start() and waits for the first set of collectors.

  • After the user fills out the dynamically generated form and clicks a submit button, the application gathers the input values.

  • It then calls the next() method on the DaVinci response object, sending the user’s input back to the server.

  • The server processes the input and responds with the next set of collectors (or a success or failure message), and the rendering cycle begins again.

    This loop continues until the flow is complete.

4. User Session Management

Upon successful completion of the DaVinci flow, the sample demonstrates how to handle the successful authentication.

  • It receives a success response from the server.

  • It displays the user’s session and token information, demonstrating that a session has been established.

  • It also renders a logout button, showing how to terminate the session using FRUser.logout().

reactjs-todo-davinci

What does the reactjs-todo-davinci sample support?
Feature Supported by sample

Orchestration

  • PingOne - DaVinci flows

Implementation

  • Embedded

Language

  • ReactJS

DaVinci Fields

  • Text

  • Password

  • Checkbox

  • Combobox

  • Dropdown

  • Label

  • Phone number

DaVinci Buttons

  • Flow button

  • Submit button

  • Social sign-on

  • Radio

DaVinci Toolbox

  • OTP device registration

  • OTP device authentication

The reactjs-todo-davinci application is a "To-Do List" single-page application (SPA) built with ReactJS.

javascript angular todo davinci sample

Its primary purpose is to demonstrate how to secure a React application by embedding a PingOne DaVinci flow directly into the user experience.

Instead of a static login form, the application initiates a DaVinci flow and dynamically renders the necessary UI components based on the collectors it receives from the server. Once a user is authenticated, they can access the protected To-Do list page, showcasing a complete, secure workflow from login to application usage.

This sample requires the javascript/todo-api sample app to act as the backend API.

The application showcases several modern, best-practice patterns for integrating the DaVinci client for JavaScript within a React project:

1. Global State Management with React Context

The application uses React’s built-in Context API for managing shared state, which is a lightweight and effective alternative to larger libraries like Redux for this use case.

  • Location: javascript/reactjs-todo-davinci/client/global-state.js

  • Function: It defines a custom hook, useGlobalStateMgmt, which encapsulates all the logic for managing shared state like isAuthenticated, username, and theme. The AppContext then makes this state and its setter functions available to any component wrapped in its provider.

    The setAuthenticationWrapper function couples the application’s state with the DaVinci client’s functionality. When a component sets the authentication state to false, this wrapper interprets it as a logout action and triggers logout(), ensuring the user’s session is properly terminated PingOne.

2. Dynamic, View-Based Routing

The application uses react-router-dom to manage navigation, with a structure that separates public and private views.

  • File: javascript/reactjs-todo-davinci/client/router.js

  • Function: The Router component defines all application routes. It makes use of a custom ProtectedRoute component to guard access to the /todos page.

    This guard checks the isAuthenticated flag from the global context and redirects unauthenticated users to the /login page.

3. Component-Driven DaVinci Flow

The login experience is not hardcoded but is driven by the DaVinci flow itself.

  • File: javascript/reactjs-todo-davinci/client/views/login.js

  • Function: The Login view acts as a container. It renders a dedicated <Form /> component (refer to javascript/reactjs-todo-davinci/client/components/davinci-client/form.js).

    This Form component is responsible for initiating the DaVinci flow, listening for collectors, and dynamically rendering the appropriate input fields, such as a username and password. This architecture makes the login UI incredibly flexible, as the entire user journey can be modified in the DaVinci flow builder without changing the React code.

angular-todo-davinci

What does the angular-todo-davinci sample support?
Feature Supported by sample

Orchestration

  • PingOne - DaVinci flows

Implementation

  • Embedded

Language

  • Angular

DaVinci Fields

  • Text

  • Password

DaVinci Buttons

  • Flow button

  • Submit button

The angular-todo-davinci application is a classic "To-Do List" single-page application (SPA) built with Angular.

javascript angular todo davinci sample

Its primary purpose is to demonstrate how to secure an Angular application using a PingOne DaVinci flow for embedded user authentication.

Instead of a static, hardcoded login form, the application initiates a DaVinci flow and dynamically renders the login UI based on the collectors it receives from the server. Once authenticated, the user can manage their to-do list, demonstrating how to protect application features and routes.

This sample requires the javascript/todo-api sample app to act as the backend API.

The application showcases modern, best-practice patterns for integrating the DaVinci client for JavaScript within an Angular project:

1. Component-Driven Authentication Flow

The DavinciFormComponent (refer to javascript/angular-todo-davinci/src/app/features/davinci/form/form.component.ts) acts as a self-contained controller for the DaVinci authentication process:

State Management is Local

The component manages the state of the DaVinci flow in its own local properties, not in a shared service. This includes the DaVinci client instance, the current node, and the collectors needed to build the form.

Flow Initialization

In ngOnInit, the component itself is responsible for creating the DaVinci client and starting the flow.

This is a key SDK integration point.

2. The Role of SdkService

The SdkService plays a different, but crucial, role. It is not responsible for the DaVinci flow itself, but rather for what happens after the flow is successfully completed:

Post-Authentication Handler

Its primary job is to take the authorization code and state from a successful DaVinci flow and use them to complete the OAuth 2.0 flow to get tokens and establish a user session.

Session Management

The successHandler method in the DavinciFormComponent is responsible for this hand-off.

3. Dynamic UI Rendering

The component’s template (refer to javascript/angular-todo-davinci/src/app/features/davinci/form/form.component.html) is responsible for dynamically rendering the correct input fields based on the collectors array, which is populated from the current DaVinci node.

This allows the UI to adapt to any changes in the DaVinci flow without requiring code changes in the Angular app.

4. Route Protection

The AuthGuard class protects routes by checking the final authentication state managed by the SdkService.