Skip to content

feat(davinci): add SOCIAL_LOGIN_BUTTON IdP collector support (SDKS-5128) - #59

Merged
pingidentity-gaurav merged 5 commits into
mainfrom
SDKS-5128
Jul 29, 2026
Merged

feat(davinci): add SOCIAL_LOGIN_BUTTON IdP collector support (SDKS-5128)#59
pingidentity-gaurav merged 5 commits into
mainfrom
SDKS-5128

Conversation

@pingidentity-gaurav

@pingidentity-gaurav pingidentity-gaurav commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds IdpCollector (SOCIAL_LOGIN_BUTTON) support to the DaVinci bridge on iOS and Android
  • Renames the collector type from the internal 'IDP' normalization to the server-native 'SOCIAL_LOGIN_BUTTON' string, matching the pattern used by all other collectors
  • Adds rawFieldKey helper for collectors whose id() doesn't match the server key field (extensible for future collectors)
  • Moves setDaVinciCollectorResolver from eager init into configureDaVinci on iOS, matching the Journey pattern
  • Hardens integrationRequiredCollectorTypes to Set<DaVinciCollector['type']> for compile-time safety
  • Adds DaVinciIdpField component and useDaVinciAutoForwarder hook to the sample app for seamless post-IdP-authorize auto-advance
  • Hides missing first/family name fields in UserProfileInfoCard

Test plan

  • Android: social login (Google/Facebook) via DaVinci flow completes without showing intermediate "Continue" button
  • iOS: same flow works on iPhone Ping device
  • Unit tests pass: yarn test --filter=@ping-identity/rn-davinci --filter=@ping-identity/rn-external-idp
  • Typecheck passes: yarn typecheck
  • No regression on Journey or OIDC user profile card

Summary by CodeRabbit

  • New Features

    • Added DaVinci social login buttons (Google, Facebook, Apple, etc.) and the ability to initiate external IdP authorization from DaVinci flows.
    • Added “User Profile” navigation available after successful authentication.
    • Automatically advances eligible sign-in steps and can restart the flow when returning after a terminal state.
  • Bug Fixes

    • Improved sign-in failure UI with consistent “Sign-in failed” messaging and a Retry action.
    • Improved profile display when profile fields are missing or unavailable.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 37e6147b-d4d3-4433-bc13-a8120a166352

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa7a96 and ccae14c.

📒 Files selected for processing (1)
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapper.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapper.kt

📝 Walkthrough

Walkthrough

Adds DaVinci social-login collectors and external IdP authorization across shared types, native bridges, form handling, the sample app, and related tests. It also adds DaVinci instance identity access, collector resolution, retry behavior, profile navigation, and iOS configuration entries.

Changes

DaVinci external IdP flow

Layer / File(s) Summary
Collector contracts and native mapping
packages/davinci/src/*, packages/davinci/android/..., packages/davinci/ios/..., packages/davinci/src/__tests__/*
Adds IdpCollector, classifies SOCIAL_LOGIN_BUTTON as integration-required, serializes it on Android and iOS, and expands mapper/form tests.
DaVinci instance and collector resolution
packages/davinci/src/..., packages/core/ios/CoreRuntime.swift, packages/types/src/index.ts, packages/davinci/RNPingDavinci.podspec, packages/external-idp/android/build.gradle, PingTestRunner/android/settings.gradle
Adds getId(), exports DaVinci context contracts, registers resolver APIs, and wires native module dependencies.
External IdP authorization bridge
packages/external-idp/*, PingTestRunner/__tests__/integration/external-idp.test.ts, PingTestRunner/android/src/test/...
Adds authorizeForDaVinci to TypeScript, Android, and iOS APIs, resolves collectors natively, propagates errors, and tests bridge behavior.
Sample app IdP and profile flow
PingSampleApp/ui/*, PingSampleApp/metro.config.js, PingSampleApp/ios/*, .gitignore
Renders branded social-login buttons, wires authorization and auto-forwarding through the panel, adds retry/profile actions, updates profile display handling, and configures local DaVinci resolution.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DaVinciIdpField
  participant DaVinciClientPanel
  participant ExternalIdpClient
  participant NativeBridge
  DaVinciIdpField->>DaVinciClientPanel: onIdpAuthorize(collector)
  DaVinciClientPanel->>ExternalIdpClient: authorizeForDaVinci(daVinci, index)
  ExternalIdpClient->>NativeBridge: authorizeForDaVinci(davinciId, options, config)
  NativeBridge-->>ExternalIdpClient: authorization result
  ExternalIdpClient-->>DaVinciClientPanel: resolve or reject
  DaVinciClientPanel->>DaVinciClientPanel: next({ collectors: [] })
Loading

Possibly related PRs

Suggested reviewers: witrisna, george-bafaloukas-forgerock

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding SOCIAL_LOGIN_BUTTON IdP collector support for DaVinci.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch SDKS-5128

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 58.25545% with 134 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.70%. Comparing base (81d22e9) to head (ccae14c).

Files with missing lines Patch % Lines
...gidentity/rnexternalidp/RNPingExternalIdpCommon.kt 0.00% 66 Missing ⚠️
...ges/external-idp/ios/RNPingExternalIdpCommon.swift 33.80% 47 Missing ⚠️
packages/core/ios/CoreRuntime.swift 42.85% 12 Missing ⚠️
...pingidentity/rndavinci/mapper/DaVinciNodeMapper.kt 87.50% 0 Missing and 2 partials ⚠️
packages/davinci/ios/RNPingDavinciCommon.swift 50.00% 2 Missing ⚠️
...nal-idp/ios/Tests/RNPingExternalIdpImplTests.swift 93.93% 2 Missing ⚠️
packages/davinci/src/davinci.ts 0.00% 1 Missing ⚠️
packages/davinci/src/useDavinci.tsx 0.00% 1 Missing ⚠️
...gidentity/rnexternalidp/RNPingExternalIdpModule.kt 0.00% 1 Missing ⚠️

❌ Your patch check has failed because the patch coverage (34.21%) is below the target coverage (60.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff              @@
##               main      #59      +/-   ##
============================================
+ Coverage     71.41%   71.70%   +0.29%     
- Complexity      181      187       +6     
============================================
  Files           154      161       +7     
  Lines         18052    18890     +838     
  Branches        539      674     +135     
============================================
+ Hits          12891    13546     +655     
- Misses         5111     5271     +160     
- Partials         50       73      +23     
Flag Coverage Δ
android 17.07% <16.86%> (-0.04%) ⬇️
ios 80.34% <72.48%> (-0.12%) ⬇️
javascript 91.31% <77.77%> (-7.28%) ⬇️
Components Coverage Δ
Bridge glue 50.97% <34.21%> (-0.04%) ⬇️
Pure logic 81.43% <95.00%> (+0.26%) ⬆️
Files with missing lines Coverage Δ
...ackages/davinci/ios/Mapper/DaVinciNodeMapper.swift 94.27% <100.00%> (+0.55%) ⬆️
...ges/davinci/ios/Tests/DaVinciNodeMapperTests.swift 99.47% <100.00%> (+0.06%) ⬆️
packages/davinci/src/collectorHelpers.ts 92.80% <100.00%> (ø)
...kages/external-idp/ios/RNPingExternalIdpImpl.swift 100.00% <100.00%> (ø)
...ckages/external-idp/src/NativeRNPingExternalIdp.ts 96.96% <ø> (ø)
packages/external-idp/src/externalIdp.ts 100.00% <100.00%> (ø)
...ckages/external-idp/src/types/externalIdp.types.ts 100.00% <ø> (ø)
packages/types/src/index.ts 96.66% <ø> (ø)
packages/davinci/src/davinci.ts 95.93% <0.00%> (ø)
packages/davinci/src/useDavinci.tsx 78.94% <0.00%> (ø)
... and 7 more

... and 3 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81d22e9...ccae14c. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-07-29 21:06 UTC

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
packages/davinci/src/types/node.types.ts (1)

385-385: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: preserve literal autocomplete on idpType.

'GOOGLE' | 'FACEBOOK' | 'APPLE' | string collapses to string in TypeScript, so editors lose autocomplete for the known providers while still accepting any string. If keeping the union open is the goal, ... | (string & {}) retains both.

♻️ Suggested change
-  idpType: 'GOOGLE' | 'FACEBOOK' | 'APPLE' | string;
+  idpType: 'GOOGLE' | 'FACEBOOK' | 'APPLE' | (string & {});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci/src/types/node.types.ts` at line 385, Update the idpType
declaration to preserve autocomplete for the known GOOGLE, FACEBOOK, and APPLE
literals while continuing to accept arbitrary strings, using the open-string
union pattern described in the review.
packages/external-idp/android/src/main/java/com/pingidentity/rnexternalidp/RNPingExternalIdpCommon.kt (1)

317-425: 📐 Maintainability & Code Quality | 🔵 Trivial

Consider extracting the shared authorize-boilerplate.

authorizeForDaVinci duplicates most of authorizeForJourney's control flow: the foreground-activity guard, parseCallbackIndex usage, scope.launchBridge wrapping, and the CancellationException / ClassNotFoundException / NoClassDefFoundError catch structure are copy-pasted verbatim, differing only in the resolved collector type and success payload. A small helper (e.g. runIdpAuthorize(promise, errorCode) { ... } wrapping the guard + catch logic, with the resolve/collector-lookup passed as a lambda) would reduce this duplication and keep future error-handling changes in one place.
[medium_effort_and_medium_reward]

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/external-idp/android/src/main/java/com/pingidentity/rnexternalidp/RNPingExternalIdpCommon.kt`
around lines 317 - 425, Extract the duplicated authorization flow from
authorizeForDaVinci and authorizeForJourney into a shared helper, such as
runIdpAuthorize, that owns the foreground-activity check, scope.launchBridge
wrapper, and CancellationException/provider-SDK/general error handling. Pass the
provider-specific collector resolution and authorization operation as lambdas,
while preserving each method’s collector type and success payload behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/davinci/android/build.gradle`:
- Around line 99-100: Make IdpCollector available at runtime for
DaVinciNodeMapper.mapCollectorPayload by changing the external-idp dependency
from compileOnly to the appropriate runtime-inclusive configuration. Preserve
the existing collector mapping behavior so apps using rn-davinci alone cannot
fail with a missing IdpCollector class.

In `@packages/external-idp/ios/RNPingExternalIdpCommon.swift`:
- Around line 302-304: The authorization flow in IdpCollector.authorize must
receive only the callback URL scheme, not the full redirect URI. Update the
callbackURLScheme construction near callConfig.redirectUri to parse and extract
its scheme while preserving nil for an empty redirect URI, then pass that value
to authorize.

In `@PingSampleApp/ios/PingSampleApp/Info.plist`:
- Around line 66-67: Update the GIDServerClientID entry in Info.plist to
reference the backend web/server OAuth client ID configuration, while preserving
GIDClientID as the iOS client ID. Use the existing backend client-ID symbol or
setting rather than GOOGLE_IOS_CLIENT_ID.

In `@PingSampleApp/ui/davinci/hooks/useDaVinciAutoForwarder.ts`:
- Around line 73-94: Prevent idpJustAuthorized from leaking past the immediate
post-authorization ContinueNode: in
PingSampleApp/ui/davinci/hooks/useDaVinciAutoForwarder.ts:73-94, call
onForwarded() when the ContinueNode cannot auto-forward due to manual input,
integration requirements, unsupported state, or !canSubmit, while preserving the
successful-forward path; in
PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts:122-131, reset
setIdpJustAuthorized(false) in onStart alongside setIdpError(null).

In `@PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts`:
- Around line 169-203: Update onIdpAuthorize to handle a missing collector match
explicitly instead of passing index 0 to authorizeForDaVinci. When findIndex
returns -1, surface an appropriate error through the existing IdP error handling
and return without authorizing; preserve the current authorization flow for
valid indices.

---

Nitpick comments:
In `@packages/davinci/src/types/node.types.ts`:
- Line 385: Update the idpType declaration to preserve autocomplete for the
known GOOGLE, FACEBOOK, and APPLE literals while continuing to accept arbitrary
strings, using the open-string union pattern described in the review.

In
`@packages/external-idp/android/src/main/java/com/pingidentity/rnexternalidp/RNPingExternalIdpCommon.kt`:
- Around line 317-425: Extract the duplicated authorization flow from
authorizeForDaVinci and authorizeForJourney into a shared helper, such as
runIdpAuthorize, that owns the foreground-activity check, scope.launchBridge
wrapper, and CancellationException/provider-SDK/general error handling. Pass the
provider-specific collector resolution and authorization operation as lambdas,
while preserving each method’s collector type and success payload behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 73a3afb5-4ff0-4d69-9705-98887b6e606e

📥 Commits

Reviewing files that changed from the base of the PR and between 81d22e9 and 2e92fe8.

⛔ Files ignored due to path filters (1)
  • PingSampleApp/ios/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (48)
  • .gitignore
  • PingSampleApp/ios/PingSampleApp/Info.plist
  • PingSampleApp/metro.config.js
  • PingSampleApp/ui/DaVinciScreen.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciFieldRenderer.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciIdpField.tsx
  • PingSampleApp/ui/davinci/components/molecules/types.ts
  • PingSampleApp/ui/davinci/components/organisms/DaVinciClientPanel.tsx
  • PingSampleApp/ui/davinci/components/organisms/DaVinciContinueNodePanel.tsx
  • PingSampleApp/ui/davinci/hooks/useDaVinciAutoForwarder.ts
  • PingSampleApp/ui/davinci/hooks/useDaVinciAutoStartEffect.ts
  • PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts
  • PingSampleApp/ui/userProfile/components/molecules/UserProfileInfoCard.tsx
  • PingTestRunner/__tests__/integration/external-idp.test.ts
  • PingTestRunner/android/settings.gradle
  • packages/core/ios/CoreRuntime.swift
  • packages/davinci/RNPingDavinci.podspec
  • packages/davinci/android/build.gradle
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapper.kt
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapperTest.kt
  • packages/davinci/ios/Mapper/DaVinciNodeMapper.swift
  • packages/davinci/ios/RNPingDavinciCommon.swift
  • packages/davinci/ios/Tests/DaVinciNodeMapperTests.swift
  • packages/davinci/src/__tests__/collectorHelpers.test.ts
  • packages/davinci/src/__tests__/useDavinciForm.test.tsx
  • packages/davinci/src/collectorHelpers.ts
  • packages/davinci/src/davinci.ts
  • packages/davinci/src/index.tsx
  • packages/davinci/src/types/client.types.ts
  • packages/davinci/src/types/node.types.ts
  • packages/davinci/src/useDavinci.tsx
  • packages/external-idp/README.md
  • packages/external-idp/android/build.gradle
  • packages/external-idp/android/src/main/java/com/pingidentity/rnexternalidp/RNPingExternalIdpCommon.kt
  • packages/external-idp/android/src/newarch/java/com/pingidentity/rnexternalidp/RNPingExternalIdpModule.kt
  • packages/external-idp/android/src/oldarch/java/com/pingidentity/rnexternalidp/RNPingExternalIdpClassicModule.kt
  • packages/external-idp/android/src/test/java/com/pingidentity/rnexternalidp/RNPingExternalIdpTest.kt
  • packages/external-idp/ios/RNPingExternalIdp.mm
  • packages/external-idp/ios/RNPingExternalIdpClassic.mm
  • packages/external-idp/ios/RNPingExternalIdpCommon.swift
  • packages/external-idp/ios/RNPingExternalIdpImpl.swift
  • packages/external-idp/ios/Tests/RNPingExternalIdpImplTests.swift
  • packages/external-idp/src/NativeRNPingExternalIdp.ts
  • packages/external-idp/src/__tests__/index.test.tsx
  • packages/external-idp/src/externalIdp.ts
  • packages/external-idp/src/types/externalIdp.types.ts
  • packages/external-idp/src/types/index.ts
  • packages/types/src/index.ts

Comment on lines +99 to +100
// Required: IdpCollector is defined in external-idp. The JS authorizeForDaVinci API is optional but this native dep is not.
compileOnly("com.pingidentity.sdks:external-idp:2.0.1")

@coderabbitai coderabbitai Bot Jul 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the mapper references IdpCollector at runtime (unconditional type check)
rg -nP -C3 '\bis\s+IdpCollector\b|collector\.idpId' \
  packages/davinci/android/src/main/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapper.kt

# Confirm external-idp is only compileOnly (not implementation/api) in the davinci module
rg -nP 'external-idp' packages/davinci/android/build.gradle

Repository: ForgeRock/ping-react-native-sdk

Length of output: 1554


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Files =="
git ls-files | rg '(^packages/davinci/|build\.gradle|Podspec$|package\.json$)' || true

echo
echo "== DaVinci Android build deps outline =="
awk '
/dependencies \{/,/^\}/ { print NR": "$0 }
' packages/davinci/android/build.gradle | sed 's/.*dependencies \{/dependencies {/; s/^\}\s*$/}/'

echo
echo "== All external-idp references =="
rg -n 'external-idp|external_idp|PingExternalIdP|IdpCollector|daVinci|DaVinci' .

Repository: ForgeRock/ping-react-native-sdk

Length of output: 5601


🏁 Script executed:

#!/bin/bash
set -euo pipefail

wc -l packages/davinci/android/build.gradle
echo
cat -n packages/davinci/android/build.gradle

echo
echo "== external-idp references in DaVinci =="
rg -n 'external-idp|external_idp|PingExternalIdP|IdpCollector|collectors|collector' packages/davinci -S

echo
echo "== DaVinci podspec dependency lines =="
rg -n 'dependency|vendored_libraries|s\.dependency|PingExternalIdP' packages/davinci/RNPingDavinci.podspec -A2 -B2

echo
echo "== external-idp Gradle and package artifacts =='
cat -n packages/external-idp/package.json
cat -n packages/external-idp/android/build.gradle

Repository: ForgeRock/ping-react-native-sdk

Length of output: 50388


🌐 Web query:

Ping Identity react native SDK rn-davinci external-idp 2.0.1 IdpCollector darnci

💡 Result:

In the context of Ping Identity orchestration and DaVinci flows, IdpCollector is a component returned by a DaVinci flow to the client application when the user needs to authenticate using an external Identity Provider (IdP) [1][2]. The references to rn-davinci, 2.0.1, and darnci appear to be specific internal naming conventions or legacy terminology [3]. The Ping Identity documentation has moved toward a unified "Ping Orchestration SDKs 2.0" framework, which integrates support for DaVinci flows and replaces older modular SDK approaches [3]. Key technical points regarding IdpCollector and external IdPs: 1. Handling External IdPs: When a DaVinci flow returns an IdpCollector, the client application must use this collector to initiate the authentication process with the chosen external IdP [1][2]. 2. Implementation: For mobile platforms (like those using React Native), this typically involves calling an authorize method on the IdpCollector [2]. This initiates the redirect or embedded flow required to authenticate the user and return to the application via a continueToken [1]. 3. Architecture: The current recommendation is to use the Ping Orchestration SDKs, which provide unified documentation for JavaScript, Android, and iOS integrations [3]. Older documentation specifically labeled "DaVinci module" has been folded into this new Orchestration SDK documentation [3]. If you are encountering errors or specific behavior related to version 2.0.1 or terms like darnci, it is recommended to ensure your project is utilizing the current Ping Orchestration SDKs, as these are the primary supported libraries for DaVinci flow orchestration [4][3].

Citations:


🌐 Web query:

com.pingidentity.sdks external-idp 2.0.1 maven IdpCollector

💡 Result:

The artifact com.pingidentity.sdks:external-idp is a component of the Ping (ForgeRock) SDK suite used for integrating external identity providers (IdPs) into applications, particularly within DaVinci orchestration flows [1][2]. Regarding your specific query about version 2.0.1 and the IdpCollector class: 1. IdpCollector Usage: The IdpCollector is a node type returned by a DaVinci flow when an authentication process requires an external IdP [3][4][5]. Your application code must be configured to handle this collector node to initiate the authentication process (e.g., by calling authorize) [3][4]. 2. Dependency Information: While documentation references version 2.0.1 in the context of DaVinci Android SDK integration [1], publicly available artifacts on Maven Central for com.pingidentity.sdks:external-idp currently list version 1.2.0 as the latest [6]. If you are working in an environment that requires 2.0.1, ensure you are using the correct repository configuration provided by Ping Identity, as orchestration SDK dependencies are sometimes distributed through specialized channels [1]. 3. Documentation: For detailed implementation guidance, including class references and code samples for handling IdpCollector nodes in Android, iOS, and JavaScript, you should refer to the official Ping Identity Developer documentation for DaVinci SDKs [1][7][3][4][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Gradle GradleUtils compileOnly handling =="
rg -n 'compileOnly|implementation|api|transitive' --glob '*.*gradle*' .

echo
echo "== Kotlin type checks runtime semantics probe only if compiler available =="
if command -v kotlinc >/dev/null 2>&1; then
  tmp="$(mktemp -d)"
  cat > "$tmp/Main.kt" <<'KT'
sealed class C
object IdpCollector : C()
class Collector
fun C.isOrDoesWork(c: C): String = when(c) {
    is IdpCollector -> "idp"
    else -> "other"
}
fun collectorWork(c: Collector?): String = when(c) {
    is IdpCollector -> "idp"
    else -> "error"
}
fun main() {
  println(Collector().let { c -> c.isOrDoesWork(c) || collectorWork(c as? Collector) })
}
KT
  kotlinc "$tmp/Main.kt" -include-runtime -d "$tmp/out.jar" 2>&1 | head -80 || true
else
  echo "kotlinc not available"
fi

Repository: ForgeRock/ping-react-native-sdk

Length of output: 13238


Make DaVinci runtime handle IdpCollector safely when external-idp is absent.

DaVinciNodeMapper.mapCollectorPayload is executed for every collector and references com.pingidentity.idp.davinci.IdpCollector directly; with external-idp marked compileOnly, it is not guaranteed to be on the consumer app’s runtime classpath. If an app uses only rn-davinci without rn-external-idp, collector mapping can fail. Guard IdpCollector at runtime or add the dependency so this required native path does not throw.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci/android/build.gradle` around lines 99 - 100, Make
IdpCollector available at runtime for DaVinciNodeMapper.mapCollectorPayload by
changing the external-idp dependency from compileOnly to the appropriate
runtime-inclusive configuration. Preserve the existing collector mapping
behavior so apps using rn-davinci alone cannot fail with a missing IdpCollector
class.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a cycle — this is the native SDK artifact com.pingidentity.sdks:davinci, not the rn-davinci RN module.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pingidentity-gaurav, thanks for clarifying — agreed. com.pingidentity.sdks:davinci is the native SDK artifact, not the rn-davinci React Native module, so making native external-idp runtime-inclusive does not create that module cycle.

The finding remains: since DaVinciNodeMapper directly references IdpCollector, compileOnly can leave that class unavailable at runtime for consumers using rn-davinci alone. The dependency should therefore use implementation rather than compileOnly.


✏️ Learnings added
Learnt from: pingidentity-gaurav
Repo: ForgeRock/ping-react-native-sdk PR: 59
File: packages/davinci/android/build.gradle:99-100
Timestamp: 2026-07-28T20:14:48.388Z
Learning: In `packages/davinci/android/build.gradle`, `com.pingidentity.sdks:davinci` is the native Android SDK artifact and is distinct from the `rn-davinci` React Native module; adding the native `com.pingidentity.sdks:external-idp` artifact as an implementation dependency does not create an RN-module dependency cycle.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +302 to +304
let collector = matching[collectorIndex]
let callbackURLScheme = callConfig.redirectUri.isEmpty ? nil : callConfig.redirectUri
let result = await collector.authorize(callbackURLScheme: callbackURLScheme)

@coderabbitai coderabbitai Bot Jul 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 3 'callbackURLScheme|redirectUri|authorizeForDaVinci' \
  packages/external-idp packages/davinci

Repository: ForgeRock/ping-react-native-sdk

Length of output: 50388


🌐 Web query:

For Ping Identity DaVinci iOS SDK version 2.0.1, does IdpCollector.authorize(callbackURLScheme:) require only a URL scheme, or does it accept a complete redirect URI?

💡 Result:

For Ping Identity DaVinci iOS SDK version 2.0.1, the IdpCollector.authorize method does not take a parameter for a redirect URI or scheme [1]. The authentication process is managed by the SDK, which relies on the configuration established in the PingOne platform and your iOS app's Info.plist [2][3]. When integrating external Identity Providers (IdPs) in your iOS application, you must configure a custom URL scheme in your app's Xcode project settings (specifically in the URL Types panel) to handle the callback after authentication [2][3]. The corresponding value (e.g., myapp://example.com) must also be set in the PingOne Form connector's Application Return URL field to ensure the IdP knows where to redirect the user upon completion [3]. The SDK automatically handles the interaction with the external IdP, and you initiate this process simply by calling authorize on the IdpCollector object [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Candidate files:"
fd -a 'RNPingExternalIdpCommon.swift|authenticate_with_external_idps|handling_uri_schemes' . | sed 's#^\./##' | head -50

echo
echo "Relevant ios Swift declarations:"
rg -n -C 4 'func authorize|authorize\(callbackURLScheme|callbackURLScheme:' packages/external-idp/ios/RNPingExternalId pCommon.swift packages 2>/dev/null || true

Repository: ForgeRock/ping-react-native-sdk

Length of output: 12733


🌐 Web query:

site:developer.pingidentity.com OrchSDKs DaVinci iOS authorize callbackURLScheme IdpCollector

💡 Result:

In the Ping Identity Orchestration (DaVinci) SDK for iOS, the IdpCollector is a component used to facilitate social sign-on (authentication with external identity providers like Apple, Google, or Facebook) [1][2]. To implement social sign-on with the IdpCollector, you must integrate the PingExternalIdp library alongside your core DaVinci dependency (such as PingDavinci) [3]. The core components of this process involve: 1. Handling URI Schemes: Because the authentication flow redirects users to an external identity provider and back to your app, you must configure a custom URL scheme in Xcode under your project's Info tab [4]. This ensures your app is correctly brought back to the foreground when the authentication process finishes [4]. 2. Using IdpCollector: When a DaVinci flow reaches an external IdP step, it returns an IdpCollector [1][5]. Your application code should detect this collector (often within a ViewModel), and call the authorize method on the IdpCollector instance to initiate the external authentication flow [1]. Example Swift usage: public func startSocialAuthentication async -> Result<Bool, IdpExceptions> { return await idpCollector.authorize } The authorize method is asynchronous and returns a result indicating whether the authentication succeeded or failed [1]. If successful, the flow typically continues; if not, it returns a failure with associated IdpExceptions [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Inspect relevant Swift implementation and config parser:"
sed -n '230,315p' packages/external-idp/ios/RNPingExternalIdpCommon.swift
echo
sed -n '240,265p' packages/external-idp/ios/Config/ExternalIdpConfigParser.swift
echo
echo "Check for callbackURLScheme parsing/normalization:"
rg -n 'callbackURLScheme|callbackScheme|parsedUrl|URL(string|path|init)|scheme' packages/external-idp/ios packages/browser/ios tests 2>/dev/null || true

echo
echo "List repo packages that define/dependency PingExternalIdP:"
rg -n 'PingExternalIdP|ExternalIdp|IdpCollector\.authorize|IdpCollector' packages -g '*.podspec' -g '*.pod' -g '*.swift' -g '*.kt' -g '*.java' -g '*.mm' | head -200

Repository: ForgeRock/ping-react-native-sdk

Length of output: 3623


🌐 Web query:

"PingExternalIdP" "IdpCollector" "authorize(callbackURLScheme:"

💡 Result:

In the Ping Identity SDKs (such as the iOS Unified SDK), the IdpCollector class provides an authorize method used to initiate authentication with an external Identity Provider (IdP) [1][2]. The method is defined as follows in Swift: open func authorize(callbackURLScheme: String? = nil) async -> Result<Bool, IdpExceptions> [1] The callbackURLScheme parameter is an optional string used to specify the custom URI scheme for returning to your application after the external authentication process completes [1]. When calling this method, you provide the scheme configured in your PingOne application settings to ensure the browser or external user-agent can successfully redirect the user back to your app [3]. Key details regarding the authorize method: - Asynchronous execution: The method is asynchronous and returns a Result type [1][2]. - Result Handling: It returns a success (indicating the authentication flow was initiated or completed as expected) or a failure, which includes IdpExceptions detailing any root causes for issues [4][2]. - Usage: It is typically invoked when your application handles an IdpCollector node received from the DaVinci orchestration flow [4][2]. - Android variance: In Android SDKs, the authorize method may require a URI parameter, such as a redirect URI string, to facilitate the callback process [5].

Citations:


Use only the callback scheme for DaVinci external IdP authorization.

IdpCollector.authorize(callbackURLScheme:) expects the custom URL scheme, but callConfig.redirectUri is passed as the full redirect URI such as com.myapp://callback. Extract the scheme before this call so the SDK can route the auth callback back to the app.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/external-idp/ios/RNPingExternalIdpCommon.swift` around lines 302 -
304, The authorization flow in IdpCollector.authorize must receive only the
callback URL scheme, not the full redirect URI. Update the callbackURLScheme
construction near callConfig.redirectUri to parse and extract its scheme while
preserving nil for an empty redirect URI, then pass that value to authorize.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We pass nil when no redirectUri is provided, which is correct — the native SDK picks the registered URL scheme from Info.plist.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pingidentity-gaurav, agreed—passing nil when redirectUri is absent is correct and should retain the SDK’s Info.plist-based scheme selection.

The finding is limited to the non-empty case: if redirectUri can be a complete URI (for example, com.myapp://callback), it should be reduced to com.myapp before passing it as callbackURLScheme. If the API contract guarantees redirectUri is already scheme-only, please let me know and I’ll withdraw the comment.

Comment thread PingSampleApp/ios/PingSampleApp/Info.plist
Comment on lines +73 to +94
useEffect(() => {
if (node?.type !== 'ContinueNode') {
lastNodeKeyRef.current = null;
return;
}
if (!enabled) return;
if (loading) return;
if (!continueNodeKey) return;
if (lastNodeKeyRef.current === continueNodeKey) return;

const { meta, canSubmit, input } = form;
if (meta.hasManual) return;
if (meta.hasIntegrationRequired) return;
if (meta.hasUnsupported) return;
if (!canSubmit) return;

lastNodeKeyRef.current = continueNodeKey;
onForwarded();
void next(input).catch(() => {
// Error state is surfaced by the useDaVinci hook.
});
}, [continueNodeKey, enabled, form, loading, next, node?.type, onForwarded]);

@coderabbitai coderabbitai Bot Jul 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

idpJustAuthorized can get stuck true, later auto-forwarding unrelated nodes (including a fresh flow's first node).

The flag is only ever cleared by onForwarded() inside the auto-forwarder's success path. If the post-authorize ContinueNode requires manual input, the effect returns early without clearing it, and nothing else (including onStart) resets it either — so it can leak into unrelated later nodes or a subsequent start(), contradicting the hook's own "only immediately after IdP authorize" / "never fires on the initial start() node" invariants.

  • PingSampleApp/ui/davinci/hooks/useDaVinciAutoForwarder.ts#L73-L94: clear the window (call onForwarded()) as soon as a ContinueNode check concludes it can't auto-forward (manual/unsupported/integration-required/!canSubmit), not only on a successful forward.
  • PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts#L122-L131: as a defense-in-depth backstop, also reset setIdpJustAuthorized(false) in onStart alongside setIdpError(null).
📍 Affects 2 files
  • PingSampleApp/ui/davinci/hooks/useDaVinciAutoForwarder.ts#L73-L94 (this comment)
  • PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts#L122-L131
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PingSampleApp/ui/davinci/hooks/useDaVinciAutoForwarder.ts` around lines 73 -
94, Prevent idpJustAuthorized from leaking past the immediate post-authorization
ContinueNode: in
PingSampleApp/ui/davinci/hooks/useDaVinciAutoForwarder.ts:73-94, call
onForwarded() when the ContinueNode cannot auto-forward due to manual input,
integration requirements, unsupported state, or !canSubmit, while preserving the
successful-forward path; in
PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts:122-131, reset
setIdpJustAuthorized(false) in onStart alongside setIdpError(null).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onForwarded clears the flag immediately when the forwarder fires. Fresh flows remount the component, resetting state. Not a real issue.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts --items all --type function --view expanded
ast-grep outline PingSampleApp/ui/davinci/components/organisms/DaVinciClientPanel.tsx --items all --type function --view expanded

printf '\n--- controller state/start/forwarder context ---\n'
rg -n -C 8 'idpJustAuthorized|setIdpJustAuthorized|onStart|useDaVinciAutoForwarder' \
  PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts

printf '\n--- controller ownership context ---\n'
rg -n -C 6 'useDaVinciClientPanelController|DaVinciClientPanel' \
  PingSampleApp/ui/davinci/components/organisms/DaVinciClientPanel.tsx \
  PingSampleApp/ui/DaVinciScreen.tsx

Length of output: 12965


@pingidentity-gaurav, thanks for clarifying. I rechecked the current control flow, and the concern still applies to the non-forwarding path:

  • onForwarded() does clear idpJustAuthorized immediately—but it is called only after the node passes every auto-forward eligibility check.
  • If the post-IdP ContinueNode has manual input, integration-required/unsupported fields, or cannot submit, the hook returns without clearing the flag.
  • The panel controller remains mounted while navigating within this flow, and onStart() currently does not reset the state either.

So remounting protects a later fresh screen instance, but not an in-place continuation after an ineligible post-authorization node. The reset should remain on those early-return paths (with the onStart reset as a backstop).

Comment thread PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts
Comment thread packages/external-idp/android/build.gradle
@tsdamas

tsdamas commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

PR reviewed. Great work! Left minor comments.

@rodrigoareis rodrigoareis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes looks good to me. Just a minor comment on the sample app.

Comment thread PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts
Comment thread PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts
@pingidentity-gaurav
pingidentity-gaurav merged commit 2670c57 into main Jul 29, 2026
29 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants