Use this skill for migrations from PingOne for Customers / PingOne CIAM to Descope. Trigger on requests such as "migrate PingOne to Descope", "PingOne CIAM to Descope", "replace PingOne for Customers", "move DaVinci flows to Descope", "PingOne customer auth migration", or questions about PingOne customer applications, populations, authentication policies, DaVinci, customer MFA, Protect, Verify, customer SSO, SCIM/provisioning, token claims, or PingOne APIs and supported client orchestration SDKs in the context of Descope. This skill is CIAM-only and must stop for workforce IAM, employee SSO, PingFederate, PingDirectory, PingAccess, PingID workforce auth, or general ForgeRock/PingOne Advanced Identity Cloud migrations unless the user explicitly says those products are in scope.
68
84%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
This skill guides migrations from PingOne for Customers / PingOne CIAM to Descope. It runs in three parts:
MIGRATION-PLAN.mdMIGRATION-STATE.md continuityDo not collapse these parts or skip ahead. The plan must be reviewed before code changes begin.
Primary references in this skill (detailed in Reference Files at the end):
references/pingone-detection-patterns.md - what to search for and optional PingOne API discovery routesreferences/implementation-nuances.md - how to implement each pathThis skill handles customer identity migrations from PingOne for Customers / PingOne CIAM to Descope. The app must authenticate external customers, members, patients, partners, buyers, citizens, or end users.
In scope: PingOne customer applications, PingOne users, PingOne populations, PingOne authentication policies, PingOne DaVinci flows, PingOne MFA for customer auth, PingOne Protect, PingOne Verify, PingOne Authorize for customer-facing authorization, Social login, Customer SSO, Customer SCIM/provisioning, Token claims, PingOne APIs/SDKs
Out of scope: Workforce IAM, Employee SSO/app launcher, PingID workforce authentication, PingFederate, PingDirectory, PingAccess, General ForgeRock/PingOne Advanced Identity Cloud migrations, Employee lifecycle / HR-driven provisioning
If analysis detects out-of-scope products, stop and explain that this PingOne CIAM-only skill is not the right migration path. Do not provide broad PingFederate, PingDirectory, PingAccess, PingID, workforce, or ForgeRock migration recipes.
CIAM only. Treat every decision through the customer-identity lens. Stop when the evidence points to employee IAM, workforce SSO, internal app-launcher access, device trust for employees, or HR-driven lifecycle management.
Flow-first. PingOne authentication policies and DaVinci flows usually map to Descope Flows. Look for journey logic, branching, connectors, risk checks, MFA, progressive profiling, account recovery, and claim-setting behavior before recommending code.
Map the PingOne hierarchy deliberately. Classify environments, applications, populations, and groups by behavior before creating Descope objects. Populations become tenants only for true customer organizations, realms, or isolated user communities; policy, segment, region, product, lifecycle, and reporting buckets usually become attributes, Flow branches, project strategy, or no object.
Use Descope SDK terms precisely. Descope Client SDKs are for web apps: Web JS, React, Vue, Angular, and Next.js. Descope Mobile SDKs are for mobile apps: Swift/iOS, Kotlin/Android, Flutter, and React Native. When replacing Ping Swift, Kotlin, or React Native SDK code, say "Descope Mobile SDK", not "client SDK".
Prefer Descope Native Flows for mobile migrations. Ping mobile SDK evidence can mean either OIDC Redirect/centralized login or embedded DaVinci orchestration. Do not assume Ping mobile equals redirect-only. When replacing mobile auth, recommend Descope Mobile SDK Native Flows as the default target for Swift/iOS, Kotlin/Android, Flutter, and React Native; handle OAuth/social, passkeys, magic links, and other browser-dependent steps through the Mobile SDK's Native Flow behavior. Ping DaVinci SDK integrations render flow inputs using application-owned native UI components, while Descope Native Flows embed a hosted Descope Flow in an in-app WebView. The user experience is embedded in both cases, but migration replaces Ping collector-rendering code with Descope's native flow view integration rather than translating each collector directly.
Ping SDK evidence is client-side/mobile, limited, and only one possible path. Ping Orchestration SDKs exist only for Kotlin/Android, Swift/iOS, JavaScript/TypeScript, and React Native TypeScript. Prioritize Swift and Kotlin evidence, especially when PingOne Protect collects native device or risk context. Do not look for nonexistent Ping orchestration SDKs in Python, Go, Node server code, Java, or .NET; in those stacks, look for generic OIDC/SAML config, token validation, REST/API calls, claims, sessions, and authorization logic. Do not assume the app imports a Ping SDK at all - many PingOne CIAM apps use generic OIDC middleware, hosted redirects, custom UI, direct REST calls, DaVinci widgets, or backend token validation. Where a client does use a Ping SDK, replace it; never keep it and merely point it at Descope.
Console-first. Prefer Descope Console, Flows, Widgets, JWT Templates, SSO Setup Suite, and tenant configuration before custom code. Code owns app integration and business authorization; Console/Flows should own the auth journey whenever possible.
MCP over memory. Verify every Descope SDK/API method against the Descope MCP before writing code. Use static guidance only after the MCP check is explicitly resolved.
Before doing anything else, check whether the Descope MCP Server is available by calling
docs_search with a simple query (e.g., "session validation").
If the tool is available: proceed to Part 2 immediately.
If the tool is not available, show this message and use AskUserQuestion to ask whether
they want to install it first:
Descope MCP is not installed.
This skill uses the Descope MCP server to look up current API signatures, SDK methods, and feature availability during migration. Without it, guidance is based on static training data, which may be stale and can produce SDK calls that don't exist.
You can install it in a few minutes at https://docs.descope.com/mcp/mcp-server (server URL:
https://mcp.descope.com). It significantly improves the accuracy of the migration output - especially for SDK lookups and flow-specific configuration.Would you like to install the MCP before we continue, or proceed without it?
docs_search again before proceeding.Do not proceed to Part 2 until this step is resolved.
Part 2 has four blocking phases:
MIGRATION-PLAN.mdConfirm the app authenticates external customers, members, patients, partners, or end users - not employees.
Proceed for: Customer registration, Customer login, Customer profile management, Passwordless login, Social login, Customer MFA, Account recovery, Risk checks, Identity verification, Customer-facing authorization, Customer-organization SSO
Stop if the app is primarily any of the out-of-scope products or use cases listed under Scope.
When stopping, explain that this skill is restricted to PingOne CIAM and ask whether the user wants a separate migration path for the detected product.
AskUserQuestion)Use AskUserQuestion to gather:
.env access tokenResolve the source configuration discovery method before Step 1 codebase analysis:
.env file is ready and the agent may read it:To use PingOne API discovery safely, please set up a temporary read-only Worker application for source inventory.
1. In PingOne Admin Console, go to Applications -> Applications and create or select a Worker application.
2. Keep it for discovery only. Worker apps are service/admin API clients; they are not customer login applications.
3. Grant the minimum read-only roles needed for inventory:
- Configuration Read Only for environment/application/config discovery, where available.
- Identity Data Read Only for populations, groups, and user-count style discovery, where available.
- DaVinci Admin Read Only only if DaVinci flow inventory is needed.
- Avoid write-capable admin roles unless your PingOne tenant has no read-only alternative. If read-only access is not possible, use manual exports or screenshots instead.
4. Enable the Worker application and use Client Credentials to obtain a short-lived access token. You can either use PingOne Console's Get Access Token action, if available, or your normal token endpoint workflow.
5. Store the token in a local, uncommitted `.env` file in this repo:
PINGONE_API_ACCESS_TOKEN=...
PINGONE_API_PATH=https://api.pingone.com
PINGONE_ENVIRONMENT_ID=...
For multiple environments, use:
PINGONE_ENVIRONMENT_IDS=env1,env2,env3
6. Tell me when the `.env` file is ready and that I may read it.
7. I will only use read-only GET requests with `Authorization: Bearer $PINGONE_API_ACCESS_TOKEN`. I will not create, update, delete, disable, import, rotate, or mutate anything in PingOne.
8. Do not commit this `.env` file. After discovery, revoke or rotate the token/Worker credentials.After the user confirms, read only the needed local .env values. Do not print secrets, write
them to MIGRATION-PLAN.md, or store them in MIGRATION-STATE.md. Use Authorization type
Bearer {{accessToken}} and only read-only GET calls from
references/pingone-detection-patterns.md -> "PingOne Read-Only API Discovery Routes".
Prefer metadata and counts before full user export. Do not create, update, delete, disable,
import, rotate, or mutate anything in PingOne during discovery.
No problem. Do you want to provide PingOne Console configuration manually instead?
Useful evidence can be typed, exported, or shared as screenshots:
- Applications and application types
- Populations and what each represents
- Groups, dynamic groups, and group membership purpose
- Custom roles, permissions, entitlements, and claims
- Resources and scopes
- Sign-on policies or DaVinci flow screenshots
- External IdPs, customer SSO, and SCIM configurationUse API or manual console facts directly in the Descope hierarchy recommendation:
If PingOne API or manual console discovery finds employee/workforce products or non-CIAM populations/apps, treat that as scope evidence and apply the CIAM scope guard before continuing.
After triage, summarize the likely migration path:
AskUserQuestion)Ask about:
Include this population question exactly:
Do PingOne populations represent true customer organizations/tenants, or are they segments/policy groups/regions/product lines?
Include this group question exactly:
Which PingOne groups grant access or permissions, which only classify or segment users, which are dynamic, which are externally managed through SSO/SCIM, and which are unused?
Summarize blockers and decisions before codebase analysis. If users/passwords, DaVinci logic, Protect decisions, Verify requirements, SSO, SCIM, or authorization are unclear, mark the gap in the plan rather than inventing an answer.
Read references/pingone-detection-patterns.md, then scan the repo for PingOne CIAM evidence.
Prefer rg; keep grep-compatible commands in notes when the user's environment needs portability.
At minimum, cover these evidence groups:
Use references/pingone-detection-patterns.md for the full command set and the high-signal
Swift/Kotlin symbols. Use references/implementation-nuances.md before recommending implementation
details.
For each hit, record:
Also scan for out-of-scope products:
grep -rni "pingfederate\|pingdirectory\|pingaccess\|pingauthorize\|pingid" . 2>/dev/nullIf found, flag that this may be outside the PingOne CIAM-only skill. Stop unless the user explicitly confirms those products are in scope for a separate migration path.
MIGRATION-PLAN.mdWrite MIGRATION-PLAN.md to the working directory using triage answers and codebase evidence. The
plan must include these sections in this order. Keep the plan specific to confirmed PingOne CIAM
surfaces; use Step 3 as the canonical feature-mapping source instead of repeating every rule.
Write 2-3 sentences explaining what PingOne CIAM behavior is being replaced by Descope.
State why this appears to be customer identity, not workforce IAM. If uncertain, list what evidence is missing.
State which source-discovery method was used: PingOne API discovery, manual Console/configuration evidence, repo-only evidence, or a partial mix. If API discovery was used, list only the read-only objects queried, such as environments, applications, populations, groups, group membership counts, dynamic group filters, roles/permissions, Resources/scopes, external IdPs, SSO, or SCIM. If manual evidence was used, list the typed details, exports, or screenshots reviewed. Summarize what this evidence implies for Descope project strategy, tenant candidates, attributes, Flow branches, role/group mappings, and any remaining uncertainties.
Use this table:
| Surface | Evidence | File/source | Confidence | Migration implication |
|---|
Use this table:
| PingOne object | Descope mapping | Evidence | Decision / rationale |
|---|---|---|---|
| Environment | Project | [environment IDs, issuer, env vars, console evidence] | [project strategy] |
| Application | Federated App, SDK/Flow integration, or service automation pattern | [application type, protocol, client ID, repo/config evidence] | [mapping by application type] |
| Population | Tenant, custom attribute, Flow branch, project split, or no object | [population ID/name usage, SSO/SCIM scope, app data boundary] | [classification result] |
| Group | Tenant role, project role, custom attribute, dynamic rule, SSO/SCIM mapping, FGA/app logic, or no object | [group usage in claims, authz, SSO/SCIM, policies, app code] | [classification result] |
Classify populations and groups using Step 3. Prefer PingOne API or manual Console discovery facts when available, but do not automatically map populations to tenants or groups to roles.
Explain whether this is Path A, Path B, Path C, or Mixed.
Use plain-English prose explaining today vs. after migration.
For every PingOne touchpoint, explain whether it maps to:
Group by functional area:
Include only confirmed features. For each one, use the matching Step 3 feature section and explain:
Split into:
Include Descope project, Flow, auth methods, JWT Template for profile/custom claims, social providers, tenants only if customer organizations exist, roles/permissions if used, Resources and Policies if protected APIs/MCP servers need scoped tokens, SSO/SCIM if used, and event/webhook/audit forwarding if used.
Use a diff table:
| Remove PingOne var | Add Descope var | Why |
|---|
Use the PingOne var list in references/pingone-detection-patterns.md and the Descope var table in
Step 1.5 item 10.
Include only if existing users exist. Document user export/import, forced re-login, dry runs in
dev/staging, and the chosen cutover option from
references/implementation-nuances.md -> User Migration and Password Cutover.
Include when populations are found. Classify each population using Step 3, state whether it maps to a tenant, attribute, Flow branch, project strategy, or no object, and document the evidence. PingOne users belong to exactly one population; do not introduce multi-tenant Descope membership unless the app already has that customer model.
This section is required when PingOne groups, roles, permissions, entitlements, group claims, SSO/SCIM group mappings, or dynamic groups are found. Classify each group using Step 3 as an access role, segmentation attribute, dynamic rule, external SSO/SCIM mapping, flattened nested group, FGA/app-side authorization concern, or no object.
Map PingOne groups, roles, permissions, entitlements, and custom claims by function. Document each claim reader, enforcement point, Descope JWT Template/RBAC/FGA/app-side target, and any claim-shape changes.
Include applicable risks:
Use phases:
After writing MIGRATION-PLAN.md, stop and tell the user:
MIGRATION-PLAN.mdhas been written to your working directory. It maps the PingOne CIAM surfaces found, lists Descope Console setup needed before testing, and calls out the decisions that affect cutover.Please review it before we start making changes. When you're ready to proceed, say so.
Do not begin execution until the user confirms.
Execute the plan in MIGRATION-PLAN.md Execution Plan order. Follow the detailed guidance below
for each step.
Context can be lost between turns. These rules keep the migration coherent.
Rule 1 - Create MIGRATION-STATE.md before touching any code.
Write MIGRATION-STATE.md to the working directory from the template below. It is the source of
truth for migration state - keep it current throughout execution.
# Migration State
_Last updated: [timestamp of last completed step]_
## Project Context
- Framework: [e.g., Next.js 15, Express + React, Flask, Go]
- Language: [TypeScript / Python / Go / Java / C# / etc.]
- Package manager: [npm / yarn / pnpm / pip / go / Maven / Gradle / dotnet / etc.]
- Migration path: [Path A: Federated App / protocol-config / Path B: Descope web Client SDK or Mobile SDK + Flow / Path C: Journey/config / Mixed]
- Migration goal: [Full cutover / Phased / Evaluating]
## PingOne Surfaces in Use
- Applications: [confirmed / not found]
- Source configuration discovery: [API completed / API partial / manual Console evidence / repo-only / skipped]
- Worker apps/admin API automation: [confirmed / not found]
- Authentication policies: [confirmed / not found]
- DaVinci flows: [confirmed / not found]
- Users/populations: [confirmed / not found]
- MFA/Protect/Verify: [confirmed / not found]
- Customer SSO/SCIM: [confirmed / not found]
- Authorize/roles/claims: [confirmed / not found]
## Populations Mapping
- Source evidence used: [API routes / manual Console evidence / repo evidence / not available]
- [population name/id]: [Tenant / custom attribute / Flow branch / project split / no object / unknown] - [rationale]
- Tenant membership model: [one tenant per migrated user from original population / multi-tenant membership confirmed / unknown]
## Groups Mapping
- Source evidence used: [API routes / manual Console evidence / repo evidence / not available]
- [group name/id]: [tenant role / project role / custom attribute / dynamic rule / SSO-SCIM group mapping / FGA-ReBAC / app-side logic / no object / unknown] - [rationale]
- Dynamic groups: [source attributes and recreated rule, or not applicable]
- External directory groups: [authoritative source and group-to-role mapping, or not applicable]
- Nested groups: [flattened effective access / FGA-ReBAC review / not applicable]
## Users and Password Cutover Decision
- Existing users: [active production / staging only / starting fresh]
- Password cutover: [first-login reset Flow / passwordless Flow / undecided]
- Password/hash export: not available from PingOne
- Forced re-login acceptable: [yes / no / undecided]
## Claims and JWT Template Requirements
- Claims read by app: [list]
- JWT Template needed: [yes/no]
- Roles/groups/permissions/entitlements: [list]
## Descope Console Checklist
- [ ] Descope project created - Project ID: [fill in]
- [ ] Flow selected/created
- [ ] Auth methods configured
- [ ] JWT Template configured for profile/custom claims
- [ ] Social providers configured, if used
- [ ] Tenants created only for true customer organizations or isolated customer communities, if any
- [ ] Roles/permissions configured, if used
- [ ] SSO Setup Suite / tenant SSO configured, if used
- [ ] SCIM/provisioning configured, if used
- [ ] Event/webhook/audit forwarding configured, if used
## Files Inventory
_All files that need to change. Update status after each step._
| File | Change | Status |
|---|---|---|
| `path/to/file` | [change] | Pending |
## Current Phase
Phase 1 - Console setup (not started)
## Next Action
Complete console setup per `MIGRATION-PLAN.md` before making code changes.
## Blockers
_(none)_
## Decisions Log
_(none yet)_Rule 2 - Re-read before every turn.
At the start of every execution turn, re-read MIGRATION-PLAN.md and MIGRATION-STATE.md before
writing code or making a migration decision.
Rule 3 - Verify context before every code change.
If the framework, migration path, triage answers, population mapping, or next step are not clear from the conversation, re-read both files before proceeding. Then output a context line:
Migration context: Next.js 15 - Mixed Path A+B - Phase 2, step 2/7 - Next: replace PingOne issuer config
If this line cannot be filled in accurately, re-read the files first.
Rule 4 - Update MIGRATION-STATE.md immediately after each step.
Mark files done in the Files Inventory, update Current Phase and Next Action, and append any non-obvious decision to the Decisions Log before moving on.
Run before generating any import, wrapper type, helper, or Management API call. Skipping produces code that compiles but fails at runtime.
1. Verify SDK exports before writing any import.
When the Descope MCP server is available, use docs_ask_question to confirm the exact method name,
option shape, and return type before writing any SDK call. Do not write a method name and add a
hedge like "verify the exact name" - verify it.
When the Descope MCP server is unavailable: resolve the package's type declarations
(node_modules/<pkg>/dist/types/ or its package.json types field) and confirm the exact export
and signature. For Go, run go doc. For Python, check SDK stubs. For Java/.NET, inspect the
installed package docs or generated IDE metadata.
This verification is for Descope SDK/API calls the migration actually needs. Do not infer Ping SDK usage from backend Python, Go, Node, Java, or .NET code; those findings are usually protocol, token validation, REST/API, claims, cookies, or authorization work.
Prefer local installed SDK types over GitHub when available. Installed packages reflect the exact version in use. If the Descope package is not installed yet, verify the package version before adding it.
This applies to every Descope SDK call you write: Flow components, hooks, session validation, logout, Management API calls, SSO, SCIM, tenant operations, roles, and user import helpers.
1a. After rewriting any module, grep for remaining PingOne imports/config.
grep -rni "pingone\|pingidentity\|davinci\|forgerock" \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \
--include="*.py" --include="*.go" --include="*.java" --include="*.cs" \
--exclude-dir=node_modules --exclude-dir=.next --exclude-dir=dist \
.Add remaining relevant hits to the work list. If the hit is an intentional migration note or
rollback reference, record it in MIGRATION-STATE.md.
2. Derive wrapper types from the actual return type. Do not infer Descope session or user shapes from PingOne token/user shapes. Read the SDK return type or validate through MCP, then build adapters only where the app needs a stable internal shape.
3. Check dependency versions before generating framework-specific code.
For Next.js: cookies() and headers() from next/headers are synchronous in v14 and async in
v15. Read package.json first. For Java, check Spring Security version. For .NET, check target
framework and auth middleware version. For Go/Python, check module/package versions.
4. When making a helper async, propagate to all callers immediately. Grep for every call site of a changed auth helper and update the cascade in the same pass.
5. Verify published package versions before writing to package manifests or running installs.
Do not reuse PingOne package versions or rely on memory. Check package registries when network is
available; otherwise use "latest" or a clearly flagged placeholder and record that it needs
verification.
Several steps require Descope Console setup that cannot be done in code. The app may compile without them but will not work correctly at runtime.
Use AskUserQuestion to ask whether they already have a Project ID and working Flow. If yes, skip
to verifying items 5-9 - those are easy to miss even for existing projects.
P.NEXT_PUBLIC_DESCOPE_PROJECT_ID.DESCOPE_PROJECT_ID.Required for user CRUD, user import, tenant operations, role/permission management, SSO/SCIM configuration, FGA/ReBAC, access keys, and most migration scripts.
DESCOPE_MANAGEMENT_KEY.NEXT_PUBLIC_ variables.A Flow is the authentication UI and journey. It is the usual target for PingOne authentication policies and DaVinci flows.
sign-up-or-in Flow for simple login/signup.MIGRATION-STATE.md.PingOne tokens often include profile fields, population IDs, groups, roles, permissions, entitlements, or custom claims. Descope tokens should include only claims the app actually reads.
email, name, picture, locale, or preferredLanguage only if
app code reads them from the token.aud or other API audience claims if downstream services validate them today.MIGRATION-STATE.md with the file or service that consumes it.Create tenants only after the Step 3 population mapping is decided. When a population maps to a tenant, assign each migrated user to the tenant created from their original PingOne population unless the app already has a confirmed multi-organization membership model.
| Variable | Where to get it | Used by |
|---|---|---|
DESCOPE_PROJECT_ID | Console -> Project settings | Server-side SDKs and token validation |
NEXT_PUBLIC_DESCOPE_PROJECT_ID | Same project ID | Browser-rendered Next.js/React providers/components |
DESCOPE_MANAGEMENT_KEY | Console -> Company -> Management Keys | User import, users, tenants, roles, SSO/SCIM, FGA |
After completing console setup: Update MIGRATION-STATE.md - check off each completed item,
record Project ID and Flow ID, and set Next Action to the first code/config change step.
Use this section to choose the integration style. Use Step 3 to map PingOne features and
references/implementation-nuances.md for framework-specific details before writing code.
Classify each code touchpoint as Path A, Path B, Path C (defined in Step 0.25), or:
Then read references/implementation-nuances.md in two passes before writing code:
Path-choice guardrails:
DESCOPE_MANAGEMENT_KEY server-only and use
NEXT_PUBLIC_DESCOPE_PROJECT_ID only for browser-rendered Descope components/providers.After completing framework code changes: Update MIGRATION-STATE.md - mark each modified file
as Done in the Files Inventory, update Current Phase and Next Action, and log non-obvious decisions.
Scan for PingOne references in non-code files after updating source files.
.env.example / .env.template / .env.sampleRemove PingOne variables that are no longer used and add only the Descope variables the chosen path
requires - see the Step 1.5 item 10 table. Use references/pingone-detection-patterns.md for the
full PingOne env-var list.
Run:
grep -rni "PINGONE_\|PING_ONE_\|PING_CLIENT\|PING_ENVIRONMENT\|PING_REGION\|PING_ISSUER\|PING_AUTH\|davinci" \
--include="*.env*" --include="*.md" --include="*.yml" --include="*.yaml" \
--include="Dockerfile" --include="*.sh" \
. 2>/dev/nullSearch all .md files for PingOne references. At minimum, update:
Check Dockerfiles, docker-compose, CI workflows, deployment templates, secrets managers, and infrastructure config for PingOne variables. Replace only variables the migration actually removes. For phased cutovers, document whether both PingOne and Descope config are temporarily needed.
Split setup into:
For production migrations, keep PingOne environment/application IDs, DaVinci flow IDs, population IDs, and export files documented for rollback and audit. Do not leave secrets in repo docs.
After completing non-code file updates: Update MIGRATION-STATE.md - mark env files, docs, CI,
and scripts done in the Files Inventory, and advance Next Action.
For each confirmed PingOne CIAM feature, write a short paragraph in the plan and execute against that mapping during code/config changes. Explain what the PingOne feature accomplishes, the best Descope approach for that goal, what is different, and what action is required. Reason about intent, not API names. The best Descope approach may be a Flow, Widget, SSO Setup Suite, JWT Template, tenant configuration, or app-side authorization rather than a direct SDK equivalent.
Only include confirmed features in customer-facing migration output. Keep out-of-scope product detections as blockers, not recipes.
| PingOne CIAM surface | Descope target | Primary migration action | Notes |
|---|---|---|---|
| PingOne environment | Descope Project | Create separate Descope projects for dev/staging/prod | Project IDs replace PingOne environment/issuer identifiers. |
| PingOne application records | Descope Federated App, SDK/Flow integration, or service automation pattern | Inventory application type, protocol, client ID, redirects, scopes, assigned policy/flow, and whether it serves users or services | Map by PingOne application type, not repo name. |
| SAML applications | Descope SAML Federated Application | Repoint metadata/certificates/ACS/entity ID from PingOne to Descope | This is the usual Path A for standards-based SAML apps. |
| OIDC Web and SPA applications | Descope OIDC Federated Application | Repoint issuer/discovery/client/redirect/JWKS/claims from PingOne to Descope | Both are OIDC apps; see the application-type table below for confidential vs public client handling. |
| Native/mobile and device applications | Descope Mobile SDK Native Flows or device-flow architecture review | Replace Ping mobile SDK, deep-link, callback, device-flow, and token handling | Ping mobile can be OIDC Sign-on/centralized browser login or DaVinci collector-based orchestration; default to Native Flows and use browser handoff only when needed. |
| Worker applications | Descope Management API with Management Key, or Access Keys/M2M for your own APIs | Replace the Worker app's client-credentials authentication - see Step 1.5 item 2 | Worker apps are service/admin automation, not normal sign-on apps; do not map them to Federated Apps or login Flows. |
| Supported Ping SDKs | Descope web Client SDK for web or Descope Mobile SDK Native Flows for mobile | Replace confirmed Swift, Kotlin, JavaScript/TypeScript, or React Native TypeScript SDK usage | Swift/Kotlin evidence is high signal, especially for Protect/device context. |
| Authentication policies and DaVinci flows | Descope Flows + Connectors | Rebuild screens, branches, MFA, risk, Verify, social, SSO, external calls, and claim-setting behavior | Request exports/screenshots when the repo only shows IDs or callbacks. |
| Users and password auth | Descope Users + Flow-based password cutover | Export/import users; choose first-login reset or passwordless authentication | PingOne cannot export passwords or password hashes. |
| Populations, groups, roles, and entitlements | Tenants, attributes, Flow branches, RBAC/FGA, JWT Templates, SSO/SCIM mappings, or app logic | Classify by business function before creating Descope objects | This is the core hierarchy decision; see the dedicated section below. |
| MFA, Protect, and Verify | Descope MFA/step-up Flows, fingerprinting riskInfo, Fraud & Risk Connectors, IDV connectors | Preserve the decision behavior: allow, step up, block, verify, notify, log, or review | These are security/product requirements, not simple SDK swaps. |
| Social login, PingOne External IdPs, customer SSO, and SCIM | Descope social providers, tenant SSO connections/SSO Setup Suite, and SCIM provisioning | Recreate provider credentials and re-point enterprise identity/lifecycle integrations | Customer/org IdPs map to tenant SSO; consumer social IdPs usually map to social login. |
| PingOne AI Agents | Descope Agentic Identity Hub Clients, Resources, Policies, and Agentic Identity | Register agent clients, map resources/scopes, and recreate delegation, approval, and audit behavior | CIAM-only when agents access customer-facing APIs/MCP servers or act for external customers. Workforce agent governance is out of scope unless explicit. |
| PingOne Resources | Descope API Resources or MCP Server Resources | Recreate each OAuth-protected API/MCP server, audience, scopes, and access rules | Use Inbound Apps or Agentic Clients when resource-scoped tokens are required; do not assume Federated Apps cover this. |
| Token claims | Descope JWT Templates and Flow custom claims | Recreate only claims the app reads | Claim names and nesting may change; update validators and tests. |
| Events, webhooks, and audit | Descope events, audit connectors, webhooks, or platform-specific audit forwarding | Update event names, payload handling, auth, and signing validation | Set up before production when compliance or automation depends on events. |
| PingOne APIs and admin automation | Descope Management API, Console configuration, token validation, or app logic | Replace only confirmed source calls and verify Descope method names with MCP | Backend Python/Go/Node/Java/.NET findings are usually protocol, token, API, claims, or authz work, not Ping SDK swaps. |
Use the hierarchy model as a starting point, then override it when evidence shows a different business function:
PingOne environment -> Descope Project
PingOne application -> Federated App, SDK/Flow integration, or service automation pattern
PingOne population -> Descope Tenant only when it is a real customer organization/community
PingOne group -> Descope role only when it grants access or permissionsDo this classification before user import, tenant creation, role creation, SSO/SCIM setup, or claim mapping. PingOne users belong to exactly one population; Descope users can belong to multiple tenants, but do not create multi-tenant memberships unless the app already supports that customer model.
Population mapping rules:
| If the population represents... | Map it to... |
|---|---|
| Customer organization, account, school, clinic, partner, realm, or isolated customer community | Descope Tenant |
| Region, market, locale, language, product line, plan, lifecycle state, beta cohort, or reporting segment | User/tenant custom attribute, Flow branch, app routing, or project strategy |
| Password, MFA, risk, or auth-policy grouping | Descope Flow/auth configuration, not tenant |
| Compliance/residency data partition | Separate project/environment strategy, plus attributes when needed |
Ask exactly:
Do PingOne populations represent true customer organizations/tenants, or are they segments/policy groups/regions/product lines?
Treat population-to-tenant mapping as likely only when SSO/SCIM, roles, admins, data access, or app
account IDs are scoped by population. Treat it as risky when population names look like US, EU,
B2C, beta, passwordless, mfa-required, retail, or mobile, or when the app never treats
the population ID as a customer/account boundary.
Group mapping rules:
| If the group represents... | Map it to... |
|---|---|
| Population/customer-scoped access, tenant admin, or permission set | Tenant-level role, when the population maps to a tenant |
| Environment/global access across populations | Project-level role |
| Segmentation, region, department, cohort, plan, lifecycle, reporting, or personalization | Attribute, Flow condition, or app-side filter |
| Dynamic membership | Source attributes plus ABAC, Flow condition, FGA/ReBAC, or app logic |
| External IdP, LDAP, or directory-managed membership | SSO/SCIM group-to-role or group-to-attribute mapping |
| Nested hierarchy | Flattened effective roles/permissions, or FGA/ReBAC if hierarchy matters |
| Unused group | No Descope object after dependency analysis |
Dropping a group requires confirming it is not used for application access, role/permission assignment, auth policies, token claims, SSO/SCIM, dynamic segmentation, delegated administration, audit, reporting, personalization, or app-side filters.
PingOne applications are configured integrations inside a PingOne environment that let PingOne manage access to a specific application. When a PingOne application is created, PingOne assigns a client ID to that application. Do not treat "application" as a generic repo/service bucket or infer the migration path only from code imports. Inventory the PingOne application record first.
For every PingOne application, record:
Map by application type:
| PingOne application type | What it usually means | Descope migration direction |
|---|---|---|
| OIDC Web or Single Page Application | Both are OIDC application clients. PingOne OIDC Web apps are confidential clients that can use a client secret; PingOne SPA apps are public clients and must not use a client secret. | Map both to a Descope OIDC Federated Application. Use the Descope Federated App client/auth type toggle to match confidential vs public-client behavior, then update issuer/discovery/client/redirect/JWKS/claims. |
| Native application | Mobile/desktop installed app using OIDC Sign-on/centralized browser login or embedded DaVinci orchestration, sometimes involved in MFA | Use Descope Mobile SDK Native Flows for Swift/iOS, Kotlin/Android, Flutter, or React Native migrations. Replace Ping collector-rendering code with Descope's native flow view integration; do not translate each collector directly or keep Ping SDK and point it at Descope. Review callback/deep links, token storage, logout, and any MFA-authenticator role before implementation. |
| SAML application | Browser app using PingOne as SAML IdP | Map first to a Descope SAML Federated Application. Configure Descope's IdP metadata/certificate/SSO URL in the app's Service Provider settings, and configure the SP ACS/entity ID in Descope. Stop if it is employee/Microsoft 365/WS-Fed/WS-Trust scope unless explicitly included. |
| Device Authorization | Input-constrained device gets user authorization through a second device | Treat as a dedicated device-flow migration or architecture review; do not collapse it into normal web login. |
| Worker | Service/admin API client using Client ID/Secret to get a short-lived OAuth 2.0 Client Credentials access token for PingOne Management APIs | See Step 1.5 item 2 and the Worker app table in references/implementation-nuances.md. Do not map Worker apps to Descope Federated Apps or login Flows. |
Action: inventory every PingOne application record and every app/service validating tokens or SAML assertions from it. Multi-application environments often need a mixed path: OIDC Web, SPA, and SAML apps usually map to Descope Federated Apps for Path A, native/mobile apps need Descope Mobile SDK/Flow work, DaVinci/policy-bound apps need Path C, and Worker apps need a separate service/admin-auth review.
PingOne AI Agents are OAuth identities for non-human actors that need credentials, ownership, resource access, delegation, approval, and audit. In Descope, model each customer-facing agent as an Agentic Identity Hub Client, then map the protected APIs or MCP servers to Resources, the allowed actions to scopes, and the least-privilege rules to Policies.
PingOne authentication policies decide which methods are allowed, when MFA is required, whether risk changes the journey, and how recovery or verification happens. Descope Flows are the primary replacement because they own screens, conditions, actions, subflows, connectors, and final token issuance.
Map policy elements:
riskInfo signals and Fraud & Risk ConnectorsAction: request policy exports/screenshots if the repo only shows OIDC config. Policy logic often lives entirely outside code.
DaVinci is journey orchestration. Do not reduce it to an SDK or flowId swap.
Inventory each DaVinci flow:
Map to Descope:
Action: if only DAVINCI_FLOW_ID, flowId, or interactionId appears in code, mark analysis
incomplete and request the DaVinci configuration before implementation.
PingOne users map to Descope users. The hard part is not the object name; it is stable identifiers, password cutover, profile fields, MFA factors, social identities, and claims.
See references/implementation-nuances.md -> User Migration and Password Cutover for the two
Flow-based cutover options and why hash import is not available.
Decide before cutover:
loginId.Action: run user export/import dry runs in dev/staging before production. In the same dry run, exercise the selected Descope Flow path: first-login password reset or passwordless authentication.
Use the hierarchy rules above; do not repeat the classification from memory. For each population, record the observed purpose, evidence, Descope target, and whether user membership remains one-population-to-one-tenant or needs confirmed multi-organization support.
Action: write a population mapping table in MIGRATION-PLAN.md and MIGRATION-STATE.md before
creating tenants, importing users, configuring SSO/SCIM, assigning roles, or changing tenant-scoped
code.
Use the hierarchy rules above; group names alone are not enough. For each group, record whether it grants access, classifies users, is calculated dynamically, is externally managed, is nested, or is unused, then migrate the effective behavior rather than only the group label.
Action: complete group classification before creating roles, JWT claim mappings, SSO/SCIM group-to-role mappings, FGA rules, or app-side authorization changes.
PingOne customer MFA maps to Descope MFA and step-up Flows. Keep MFA in the auth journey unless the app has a confirmed post-login factor-management requirement.
Map:
Action: identify whether MFA is mandatory, optional, risk-triggered, tenant-specific, or role-based. Recreate that decisioning in Flow logic.
Preserve the Protect decision (block / challenge / score / notify / log), not just the signal.
Use built-in fingerprinting (riskInfo) first; add Fraud & Risk Connectors when the policy needs
specialized bot, device, IP, phone, breach, or behavioral risk. Docs:
https://docs.descope.com/fingerprinting,
https://docs.descope.com/connectors/connector-configuration-guides/fraud.
Record: decision type, which signals matter, where the decision is made (policy / DaVinci / app / analytics), which journey points are affected, acceptable friction, and whether an iOS Swift or Android Kotlin SDK collects device information, device ID, behavioral signals, browser/session context, or Protect payloads before/during login.
Mobile Protect evidence is high signal. Use references/pingone-detection-patterns.md for the
Swift/Kotlin symbols. If mobile SDK code is collecting Protect/device context, do not treat it as
generic login SDK code - preserve the purpose of that collection when designing Descope
fingerprinting, Fraud & Risk Connectors, and Flow branches.
For the riskInfo signal-to-Flow mapping and the Fraud & Risk Connector catalog, see
references/implementation-nuances.md -> PingOne Protect Replacement.
Decision mapping: risk branch -> Flow conditions; challenge -> MFA/OTP/CAPTCHA; block -> deny with no session; allow -> success / skip extra MFA; notify/log -> connector, webhook, or audit forwarding.
Action: treat Protect as a design checkpoint, not a toggle (unless it only logs). Test low-, medium-, and high-risk plus bot, impossible-travel, and trusted-device paths before cutover.
PingOne Verify is an identity-proofing service used to confirm that a user is a real person and that their claimed identity matches a government-issued document. A Verify journey may collect a passport, driver's license, or other identity document, extract and validate document data, capture a selfie, compare the selfie with the document photo, perform liveness checks, and return a pass, fail, or review result. PingOne Verify may therefore support business or compliance requirements such as KYC, age verification, patient or member verification, marketplace trust, fraud prevention, or regulated onboarding.
Descope does not provide a first-party identity-verification service equivalent to PingOne Verify. Instead, rebuild the verification journey using a Descope Flow and a supported KYC or face-verification connector.
Preferred mapping:
The Incode connector is the strongest general replacement because it can provide a complete external identity-proofing journey, including government-document verification, selfie comparison, and verification outcomes that can be consumed by a Descope Flow.
The AWS Rekognition connector can be used for narrower face-verification requirements. It can compare a captured selfie with a previously registered identity image and return confidence scores. However, it does not validate the authenticity of the government document and should not be treated as a complete KYC or PingOne Verify replacement.
Action: identify the legal, compliance, fraud, or business requirement currently satisfied by PingOne Verify. Prefer the Incode connector for full identity-proofing requirements. Use AWS Rekognition only when face comparison is sufficient. For unsupported provider-specific requirements, integrate another external identity-verification provider through a custom Descope Flow connector.
PingOne social providers map to Descope social provider configuration plus Flow steps.
Action:
This is usually Console/Flow work plus claim testing, not custom SDK code.
Customer SSO maps to Descope tenant SSO only when the customer organization model is real. If the current app uses populations as policy groups, do not create tenants solely for SSO until the account model is clarified.
PingOne External IdPs usually map here when they represent a customer's SAML or OIDC IdP. In PingOne, an external IdP can appear in login, identifier-first, or external-IdP authentication policy steps. In Descope, configure the customer's IdP as one or more tenant-level SSO connections, then route users by SSO domain, tenant slug/ID, or Flow logic. If the PingOne external IdP is a consumer/social provider instead of a customer organization IdP, map it to Descope social login instead.
Prefer:
Action: identify each customer IdP, domains, certificates/secrets, ACS/callback URLs, and whether setup is internal-admin-driven or customer-self-serve.
SCIM is a lifecycle, not a one-time import. Enterprise directories will continue to create, update, suspend, delete, and group users after cutover.
Map:
Action: re-point every customer directory before production cutover or provisioning silently breaks. Test create, update, deactivate, group change, and reactivation in staging.
PingOne Resources represent OAuth-protected API endpoints with scopes, attribute mappings, and
optional PingOne Authorize permissions. Descope Resources are the same basic concept: an OAuth
resource server with an audience (aud) and a scope catalog that clients request and APIs enforce.
Map each PingOne Resource to a Descope API Resource unless it protects an MCP server, in which case
use a Descope MCP Server Resource. Recreate resource identifiers/audiences, scopes, role or policy
rules, user-attribute sharing, and token validation checks for aud and scope. If an application
needs tokens scoped to a Descope Resource, model the client as an Inbound App or Agentic Client;
Federated Apps are not the right target for Resource association.
Action: inventory each protected API/MCP server, requested scopes, granted scopes, API enforcement points, and any PingOne Authorize permission mapping before updating token validators.
PingOne Authorize for customer-facing authorization maps based on enforcement model. Do not confuse this with a standalone PingAuthorize product migration unless the user explicitly includes it.
Classify:
Action: document each role, group, permission, entitlement, policy, resource, and enforcement point. For FGA/ReBAC, require a dedicated schema review before writing implementation code.
PingOne custom claims often glue the app together. Descope JWT Templates recreate claims the app actually reads.
Map claims using the claim table in references/implementation-nuances.md -> Claim Mapping.
Action: list every claim reader in the plan. Do not ship code that expects email, groups, roles,
or population fields until the JWT Template is configured and tested.
PingOne events may drive downstream automation, analytics, compliance, audit logs, lifecycle sync, or notifications.
Map:
Action: identify business-critical events and set up Descope forwarding before production. Default to the Audit Webhook Connector for a 1:1 replacement of PingOne's generic webhook - deploy an endpoint, set auth + HMAC signing, and confirm events land. Only reach for a named connector (Datadog, Splunk, etc.) if the org is already standardized on that specific platform; don't build a custom endpoint just to re-implement what a dedicated connector already does out of the box. The app can appear to work while compliance or automation silently breaks.
Ping Orchestration/OIDC SDKs appear in client-side web or mobile code for Kotlin/Android, Swift/iOS, JavaScript/TypeScript, and React Native TypeScript. Do not look for or plan a replacement of Ping orchestration SDKs in Python, Go, Node server code, Java, or .NET.
For every confirmed PingOne API or supported SDK call found, decide whether it should become:
If the source is a Ping mobile/OIDC SDK, the migration replaces that SDK. Do not write a plan that keeps Ping SDK and only changes discovery endpoint, issuer, client ID, or redirect URI to Descope. Do not assume Ping mobile SDK usage was redirect-only: OIDC Redirect modules usually indicate centralized-login redirects, while DaVinci orchestration modules may indicate embedded, server-driven mobile flows. In both cases, recommend Descope Mobile SDK Native Flows as the default mobile migration target.
Classify backend Python, Go, Node, Java, and .NET findings as OIDC/SAML config, JWT validation, session handling, PingOne REST/API calls, claims, or Management API automation. Do not describe them as SDK-replacement work.
Action: verify every Descope method name through MCP before writing code. Prefer Console/Flow configuration for auth journey behavior.
If any product listed under Scope as out of scope appears - plus PingAuthorize as a standalone product migration - stop and ask for explicit scope confirmation.
Suggested stop message:
I found evidence of Ping workforce or platform products outside PingOne CIAM. This skill is scoped only to PingOne for Customers / PingOne CIAM migrations. I should not continue with this migration path because I may not be able to provide the most accurate migration information for these features.
Always cover these in MIGRATION-PLAN.md, MIGRATION-STATE.md, and MIGRATION-SUMMARY.md when
they apply:
flowId;
request PingOne policy or DaVinci exports when journey behavior is not visible in repo.DESCOPE_MANAGEMENT_KEY server-only and out of browser/mobile clients.Run the app and verify it works. Do not hand over only a checklist.
grep -rni "pingone\|pingidentity\|davinci\|forgerock\|PINGONE_\|PING_ONE_\|PING_CLIENT\|PING_ENVIRONMENT\|PING_REGION\|PING_ISSUER\|PING_AUTH" \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \
--include="*.py" --include="*.go" --include="*.java" --include="*.cs" \
--include="*.env*" --include="*.yml" --include="*.yaml" \
--exclude-dir=node_modules --exclude-dir=.next --exclude-dir=dist \
.If this returns results, classify each one as migrated, intentional docs/rollback, or remaining work. Do not proceed with production-ready status while unclassified PingOne references remain.
Also run the out-of-scope sweep:
grep -rni "pingfederate\|pingdirectory\|pingaccess\|pingauthorize\|pingid" . 2>/dev/nullStop if it reveals unhandled out-of-scope products.
npm install # or: pip install -r requirements.txt / go mod tidy / mvn install / dotnet restorenpx tsc --noEmit
go test ./...
mvn test
./gradlew test
dotnet testUse the project's actual commands from package.json, go.mod, pyproject.toml, pom.xml,
Gradle files, or solution files. Do not proceed until compilation/tests for touched areas pass or
failures are understood and recorded.
Start the server with the project's normal command and verify it stays running.
Auth-related failures usually mean:
populationId after it moved to tenant/custom attribute/Flow branch.Verify:
Decode a test session token only for verification, not app logic. Confirm email, name,
population/tenant strategy claims, roles, permissions, entitlements, and custom claims match the
plan.
## Test Results
**Compile/static checks:** Pass/fail with command output summary
**Existing tests:** N passed / N failed
**Server startup:** Started on port X / failed
**Unauthenticated protected route:** 302 or 401 / unexpected
**Login:** Descope Flow/OIDC starts and completes / blocked
**JWT claims:** Present / missing
**MFA/Protect/Verify:** Tested / not applicable / blocked
**SSO/SCIM:** Tested / not applicable / blocked
**Webhooks/events:** Tested / not applicable / blocked
**Blockers before going live:**
- [ ] ...Do not proceed to Step 6 until all critical auth paths either pass or are explicitly marked as manual blockers.
Every migration produces MIGRATION-SUMMARY.md covering what was done, manual setup remaining, and
behavioral differences that matter before production.
MIGRATION-SUMMARY.mdWrite a numbered migration guide in Markdown, scoped to the user's stack and confirmed PingOne CIAM
surfaces. Use code snippets only after SDK/API names are verified. Always include
MIGRATION-SUMMARY.md after execution.
For complex migrations - DaVinci, Protect, Verify, SCIM, customer SSO, Authorize/FGA, ambiguous population mapping, or multi-service token validation - flag the high-effort items explicitly with complexity (Low/Medium/High) so the user can plan.
references/pingone-detection-patterns.md - grep patterns, PingOne read-only API discovery routes,
package/import hints, env var hints, OIDC/SAML hints, DaVinci hints, and out-of-scope detection.references/implementation-nuances.md - path selection, Federated App/protocol compatibility, web Client SDK/Mobile SDK/Flow
migration, token validation, claim mapping, framework notes, Console-first decisions, and testing notes.d888111
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.