# Pingone To Descope

> 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.

- Skill: `descope/pingone-to-descope` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add descope/pingone-to-descope`
- Raw SKILL.md: https://api.skillmd.com/api/skills/descope/pingone-to-descope/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: descope (https://skillmd.com/u/descope)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/descope/pingone-to-descope

---


# PingOne CIAM -> Descope Migration Skill

This skill guides migrations from PingOne for Customers / PingOne CIAM to Descope. It runs in
three parts:

1. **MCP Check** - confirm whether the Descope MCP Server is available
2. **Migration Plan** - confirm CIAM scope, triage PingOne surfaces, analyze the codebase, and write `MIGRATION-PLAN.md`
3. **Execution** - only after the user reviews the plan, execute with `MIGRATION-STATE.md` continuity

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 routes
- `references/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](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_search` again 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:

1. CIAM scope guard
2. PingOne surface triage
3. Engineer review checkpoint
4. 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:

1. Backend language/framework.
2. Migration goal: full cutover, phased/incremental, or evaluating.
3. Existing user base: active production users, staging/dev only, or starting fresh.
4. Source configuration discovery method:
   - PingOne API discovery from a local `.env` access token
   - Manual PingOne Console/configuration evidence through typed details, exports, or screenshots
   - Skip source configuration discovery for now
5. 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 `.env` file is ready and the agent may read it:

```markdown
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:

```markdown
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:

```bash
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.md` has 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.

```markdown
# 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.**

```bash
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](https://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-in` Flow 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`, or `preferredLanguage` only if
  app code reads them from the token.
- Add legacy PingOne identifiers only if the app needs them for a migration bridge.
- Add `aud` or other API audience claims if downstream services validate them today.
- Record every claim in `MIGRATION-STATE.md` with 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:

1. **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.
2. **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_KEY` server-only and use
  `NEXT_PUBLIC_DESCOPE_PROJECT_ID` only 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)
