PingOne CIAM -> Descope Migration Skill
This skill guides migrations from PingOne for Customers / PingOne CIAM to Descope. It runs in three parts:
- MCP Check - confirm whether the Descope MCP Server is available
- Migration Plan - confirm CIAM scope, triage PingOne surfaces, analyze the codebase, and write
MIGRATION-PLAN.md - Execution - only after the user reviews the plan, execute with
MIGRATION-STATE.mdcontinuity
Do 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 path
Scope
This 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.
Guiding Principles
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.
Part 1: MCP Check (BLOCKING)
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?
- If they choose to install: pause and wait. Once they confirm it's installed, re-check by calling
docs_searchagain before proceeding. - If they choose to proceed without it: continue, but flag any SDK-specific answers as "based on last known documentation - verify against the current SDK."
Do not proceed to Part 2 until this step is resolved.
Part 2: Migration Plan
Part 2 has four blocking phases:
- CIAM scope guard
- PingOne surface triage
- Engineer review checkpoint
- Codebase/config analysis and
MIGRATION-PLAN.md
Step 0: CIAM Scope Guard (BLOCKING)
Confirm 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.
Step 0.25: PingOne Surface Triage (BLOCKING - requires AskUserQuestion)
Use AskUserQuestion to gather:
- Backend language/framework.
- Migration goal: full cutover, phased/incremental, or evaluating.
- Existing user base: active production users, staging/dev only, or starting fresh.
- Source configuration discovery method:
- PingOne API discovery from a local
.envaccess token - Manual PingOne Console/configuration evidence through typed details, exports, or screenshots
- Skip source configuration discovery for now
- PingOne API discovery from a local
- PingOne CIAM capabilities in use, as a multi-select:
- OIDC/OAuth application login
- Embedded/custom login UI
- iOS Swift Ping Orchestration/OIDC SDK
- Android Kotlin Ping Orchestration/OIDC SDK
- PingOne Protect mobile SDK/device info collection
- JavaScript/TypeScript Ping SDK or DaVinci widget
- React Native TypeScript Ping SDK
- DaVinci flows
- Authentication policies
- Users and populations
- Password login
- Passwordless / OTP / magic link
- Social login
- Passkeys / WebAuthn
- PingOne MFA
- PingOne Protect
- PingOne Verify
- PingOne Authorize
- PingOne Resources / API scopes
- PingOne External IdPs
- PingOne AI Agents
- Customer SSO
- SCIM / provisioning
- Worker app / client credentials / admin API automation
- Custom claims
- Webhooks/events
- Other
Resolve the source configuration discovery method before Step 1 codebase analysis:
- If the user chooses PingOne API discovery, show this exact setup guidance and wait until the
user says the
.envfile 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.
- If the user declines API discovery, ask this follow-up:
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 configuration
- If the user skips source configuration discovery, continue with repo evidence and mark hierarchy, group, role, SSO/SCIM, and authorization mapping confidence lower when evidence is incomplete.
Use API or manual console facts directly in the Descope hierarchy recommendation:
- Populations with real customer/org boundaries, SSO/SCIM, delegated admins, data isolation, or app account boundaries are tenant candidates.
- Populations that only represent region, policy, lifecycle, product, or reporting segments are attributes, Flow branches, project strategy, or no Descope object.
- Population-level access groups often become tenant roles or tenant-scoped attributes.
- Environment-level access groups may become project roles, global attributes, FGA/app logic, or JWT claims depending on enforcement.
- Dynamic groups usually become source attributes plus Flow conditions, ABAC/FGA, or app logic.
- External groups usually remain authoritative through SSO/SCIM group mapping.
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:
- Path A: Federated App / protocol-config migration - generic OIDC/SAML middleware can trust Descope as IdP first; never keep Ping SDKs and point them at Descope
- Path B: Descope web Client SDK or Mobile SDK + Flow migration - Ping SDK, DaVinci SDK/widget, custom UI, or direct auth API code is replaced with the correct Descope web or mobile SDK + Flow
- Path C: Journey/config migration - PingOne auth policies or DaVinci-heavy usage becomes Descope Flows + Connectors
- Mixed path - more than one path applies across apps/services
Step 0.5: Engineer Review Checkpoint (BLOCKING - requires AskUserQuestion)
Ask about:
- Descope Console access and Project ID
- Whether a Management Key is required
- PingOne admin/API access
- PingOne Worker apps, client credentials, or admin/service automation
- Existing users and password cutover
- PingOne populations and what they represent
- Whether each population is a customer organization/realm, isolated user community, segment, policy bucket, region, product line, or lifecycle bucket
- Token claims currently read by the app
- Roles, groups, permissions, and entitlements
- Which groups grant access, which groups classify users, which are dynamic, and which are externally managed through SSO/SCIM
- Multiple environments
- Multiple apps or services validating PingOne tokens
- Maintenance window or zero-downtime requirement
- Whether users can be forced to log in again after cutover
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.
Step 1: Codebase + Config Analysis
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:
- PingOne/Ping Identity/DaVinci/ForgeRock strings and PingOne URLs.
- Swift/iOS and Kotlin/Android Ping SDK imports and dependencies, including Protect/device-context patterns.
- JavaScript/TypeScript Ping or DaVinci SDK/widget usage.
- Generic OIDC/OAuth/SAML config: issuer, discovery, JWKS, metadata, client ID/secret, redirect, callback, ACS, token, and logout settings.
- PingOne env vars, Worker app/client-credentials variables, and deployment/secrets config.
- User/profile, population, group, role, permission, entitlement, claim, MFA, Protect, Verify, social, SSO, SCIM, webhook, event, and audit references.
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:
- File path and line
- What it does
- Which PingOne surface it suggests
- Whether it maps to code, Console/Flow config, data migration, or architecture review
- Complexity: Low / Medium / High
Also scan for out-of-scope products:
grep -rni "pingfederate\|pingdirectory\|pingaccess\|pingauthorize\|pingid" . 2>/dev/null
If 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.
Step 2: Write MIGRATION-PLAN.md
Write 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.
Overview
Write 2-3 sentences explaining what PingOne CIAM behavior is being replaced by Descope.
CIAM Scope Confirmation
State why this appears to be customer identity, not workforce IAM. If uncertain, list what evidence is missing.
Source Configuration Discovery
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.
PingOne Surfaces Found
Use this table:
| Surface | Evidence | File/source | Confidence | Migration implication |
|---|
PingOne -> Descope Hierarchy Mapping
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.
Migration Path
Explain whether this is Path A, Path B, Path C, or Mixed.
What's Changing and Why
Use plain-English prose explaining today vs. after migration.
Client Integration vs Backend Validation vs Console/Flow Mapping
For every PingOne touchpoint, explain whether it maps to:
- Descope web Client SDK / web component / React/Next SDK for browser auth UI
- Descope Mobile SDK Native Flow integration for Swift/iOS, Kotlin/Android, Flutter, or React Native mobile auth
- Descope backend token/session validation or Management API, where server-side work is actually needed
- Descope Console / Flow / JWT Template / Widget / SSO Setup Suite
- App-side authorization logic
Auth Touchpoints: What the Code Analysis Found
Group by functional area:
- Login / signup
- Callback / redirect / OIDC
- Session validation
- Token claims
- API resources / scopes
- User profile
- MFA / step-up
- Social login
- SSO
- Authorization
- AI agents / agent access
- Webhooks/events
PingOne Feature Migration
Include only confirmed features. For each one, use the matching Step 3 feature section and explain:
- What the PingOne feature does today.
- The Descope target: Federated App, Flow, Connector, tenant config, JWT Template, Widget, Resource, Policy, Inbound App, Agentic Client, Management API, RBAC/FGA, or app-side authorization.
- Required code/config/data changes.
- Complexity and unresolved decisions.
Required Descope Configuration
Split into:
- Required before testing
- Required before production
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.
Environment Variables
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.
User and Password Cutover
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.
Population / Tenant / Attribute Mapping
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.
Group / Role / Attribute Mapping
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.
Claims, Roles, and Authorization
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.
Risks and Things to Decide
Include applicable risks:
- Workforce IAM out of scope
- Source configuration discovery declined, unavailable, or partial; hierarchy and role mapping confidence may be lower
- Populations are not automatically tenants
- Groups are not automatically roles
- DaVinci flows may hide important journey logic outside the app repo
- OIDC apps may have little Ping-specific code
- Protect may affect user friction and security decisions
- Verify may be a business requirement, not just auth
- Claims will change
- Password cutover must be decided before cutover: first-login reset Flow or passwordless Flow
- Active PingOne sessions will not automatically survive
Execution Plan
Use phases:
- Console setup
- Code/config changes
- User/password cutover
- Testing
- Production cutover
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.
Part 3: Execution
Execute the plan in MIGRATION-PLAN.md Execution Plan order. Follow the detailed guidance below
for each step.
Context Continuity Protocol
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.
Pre-Generation Protocol (apply before writing any code)
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.
Step 1.5: Descope Project Setup & Console Configuration
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.
1. Create a project and get your Project ID
- Sign in at console.descope.com.
- Your Project ID appears in the project selector and under Project settings. It starts with
P. - For browser-rendered Next.js/React code, this becomes
NEXT_PUBLIC_DESCOPE_PROJECT_ID. - For server-side SDKs, this becomes
DESCOPE_PROJECT_ID. - Create separate projects for dev/staging/prod if the PingOne setup has separate environments.
2. Get a Management Key (if needed)
Required for user CRUD, user import, tenant operations, role/permission management, SSO/SCIM configuration, FGA/ReBAC, access keys, and most migration scripts.
- If the source uses a PingOne Worker application to call PingOne Management APIs, replace the Worker app Client ID/Client Secret + OAuth 2.0 Client Credentials token exchange with a Descope Management Key. Descope management calls authenticate directly with the Management Key; there is no Client Credentials token exchange.
- Console -> Company -> Management Keys -> create a Management Key.
- Store as
DESCOPE_MANAGEMENT_KEY. - Treat it like a secret. Never expose it in client-side code or
NEXT_PUBLIC_variables.
3. Choose or create a Flow
A Flow is the authentication UI and journey. It is the usual target for PingOne authentication policies and DaVinci flows.
- Console -> Flows.
- Start with the built-in
sign-up-or-inFlow for simple login/signup. - Duplicate and customize it when PingOne policies, DaVinci logic, MFA, Protect, Verify, or progressive profiling require branching.
- Record the Flow ID in
MIGRATION-STATE.md. - For DaVinci-heavy migrations, do not create a custom Flow until the DaVinci graph, connectors, conditions, and claim-setting steps are understood.
4. Configure authentication methods
- Console -> Authentication methods.
- Configure only the methods confirmed in triage: password, OTP, magic link, social, passkeys, WebAuthn, SSO, MFA, or passwordless.
- For social providers, recreate provider credentials in Descope and add provider steps to the Flow.
- For customer SSO, configure tenant SSO or the SSO Setup Suite after tenant strategy is confirmed.
5. Configure a JWT Template
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.
- Console -> JWT Templates.
- Add profile claims such as
email,name,picture,locale, orpreferredLanguageonly if app code reads them from the token. - Add legacy PingOne identifiers only if the app needs them for a migration bridge.
- Add
audor other API audience claims if downstream services validate them today. - Record every claim in
MIGRATION-STATE.mdwith the file or service that consumes it.
6. Create tenants for true customer organizations or isolated customer communities
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.
7. Create roles and permissions (if using authorization)
- Console -> Authorization -> RBAC.
- Create only the project-level roles, tenant-level roles, permissions, FGA objects, or app-side authorization changes selected in the Step 3 group/authorization mapping.
- Preserve segmentation groups as attributes, dynamic groups as rules, and external SSO/SCIM groups as authoritative mappings rather than blanket role imports.
8. Configure customer SSO and SCIM (if used)
- For true customer organizations, configure tenant SSO.
- Prefer SSO Setup Suite when customer admins self-configure SAML/OIDC and SCIM.
- Treat SCIM/provisioning as a continuing lifecycle, not a one-time import.
- Confirm group-to-role mapping, deprovisioning behavior, and whether SCIM was scoped by population.
9. Configure events, webhooks, audit forwarding, Protect, and Verify replacements (if used)
- Recreate only confirmed event/webhook/audit flows.
- For Protect, decide whether Descope built-in fingerprinting signals, Fraud & Risk Connectors, Flow risk branching, webhooks, or an external provider replace the current behavior.
- For Verify, decide whether Descope Flow orchestration plus an external IDV provider is required.
10. Env var summary
| 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.
Step 2: Framework-Specific Migration
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:
- Token/API-only backend work - APIs/services validate PingOne tokens, read claims, call PingOne REST/Admin APIs, or enforce authorization; this is not a Ping SDK swap.
Then read references/implementation-nuances.md in two passes before writing code:
- General sections - Path Selection (per-path work and risk), Federated App/protocol migration, web Client SDK/Mobile SDK/Flow migration, token validation, claim mapping, Console-first decisions. These carry the implementation detail for each path; do not restate it from memory.
- Framework section - read only the section matching the user's stack.
Path-choice guardrails:
- Path A applies only when a generic OIDC/OAuth/SAML client is pointed at PingOne as the IdP. Do not use it for Swift/Kotlin/React Native/JavaScript code that imports Ping Orchestration, Ping OIDC, or DaVinci SDKs - that SDK must be replaced, usually Path B plus Path C.
- Path A is a good first phase for a phased migration, but PingOne authentication policies, DaVinci flows, Protect, Verify, customer SSO, SCIM, and user/password cutover may still need separate work.
- Do not choose Path B only because a Python, Go, Node API, Java, or .NET service validates PingOne tokens.
- For Path B mobile work, record client ID, scopes, redirect/deep link, discovery endpoint, browser/session mode, token storage, refresh/logout, callbacks, and any device/risk payload handoff before replacing the SDK.
- For Path C, request DaVinci exports/screenshots and authentication policy details, and inventory screens, nodes, connectors, conditions, risk branches, Verify/MFA steps, progressive profiling, claims, and side effects before rebuilding. Keep custom business logic in the app only when it belongs after session validation.
Framework routing notes
- Browser/React/Next apps may use Path A when they already use generic OIDC middleware, or Path B
when they render/own the auth UI. Keep
DESCOPE_MANAGEMENT_KEYserver-only and useNEXT_PUBLIC_DESCOPE_PROJECT_IDonly for browser-rendered Descope components/providers. - Node, Python, Go, Java, and .NET backends usually need issuer/JWKS/audience/claim validation, cookie/session, REST/API, or Management API updates. Do not describe these as Ping orchestration SDK replacements.
- Native Swift/Kotlin/Flutter/React Native apps use Descope Mobile SDK Native Flows and require mobile-specific callback/deep-link, token storage, logout, and Protect/device-context review.
- Ping DaVinci collector-based mobile UI maps to Descope Native Flows. Ping OIDC Sign-on / centralized browser login can still use Native Flows, with mobile browser flow / browser handoff only for auth methods or product requirements that need external/system browser behavior.
- Verify all Descope SDK/API method names through MCP or local type declarations before generating code.
**Af
…(truncated)