# Workos To Descope

> Use this skill whenever anyone asks about migrating from WorkOS to Descope — whether they're a developer doing it themselves or a technical lead evaluating the move. Triggers on: "how do I migrate from WorkOS", "replace WorkOS with Descope", "we're moving off WorkOS", "WorkOS to Descope", "switch from WorkOS", "our app uses @workos-inc/node / @workos-inc/authkit-nextjs / AuthKit / WorkOS SSO / Directory Sync / SCIM and we want to use Descope instead", or any question about WorkOS features (AuthKit, Organizations, Enterprise SSO, Directory Sync/SCIM, Admin Portal, RBAC, FGA, Audit Logs, Radar, Pipes) in the context of Descope. Works for any language or framework with a Descope SDK. Always use this skill before producing migration guidance — do not rely on memory alone.

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

---


# WorkOS → Descope Migration Skill

This skill guides self-service migrations from WorkOS to Descope. It runs in three parts:

1. **MCP Check** — confirm whether the Descope MCP Server is available and suggest installing it if not
2. **Migration Plan** — gather context via triage questions, analyze the codebase's auth touchpoints, and produce a human-readable `MIGRATION-PLAN.md` for the user to review
3. **Execution** — if the user confirms they want to proceed, execute the plan

Do not collapse these parts or skip ahead. The plan must be reviewed before code changes begin.

WorkOS is not only an authentication provider — it is a B2B/enterprise-readiness platform spanning
authentication, organizations, enterprise SSO, SCIM/directory sync, RBAC, FGA, audit logs, connected
accounts, admin setup flows, and security controls. A good migration first identifies which WorkOS
features are in use, then maps each one to the closest Descope feature or migration pattern. Expect
WorkOS migrations to be more B2B-enterprise heavy than a typical consumer-auth migration.

**Primary references** (both in this skill's directory):

- `references/implementation-nuances.md` — verified migration patterns for each framework, WorkOS feature-to-Descope mappings, and known gotchas
- `references/flows-and-widgets.md` — Descope terminology/lingo, Flow structure and templates, Widgets, SSO Setup Suite, Console-vs-code decision guide

---

## Guiding Principles

**Console-first.** Before recommending SDK code for any user-facing auth feature, check whether the Console, a Flow, a Widget, or the SSO Setup Suite covers the use case. Engineers integrate once (SDK setup + session validation). All subsequent auth evolution — new methods, MFA changes, UI updates, tenant SSO onboarding — should happen in the Console without code deployments. See `references/flows-and-widgets.md` → Console vs. Code.

**Ask, don't assume.** At any design decision point — embed Flows vs. OIDC compatibility, Flow vs. custom code, Widget vs. custom page, MFA inline vs. separate enrollment, programmatic SSO vs. SSO Setup Suite, one-Organization-to-one-Tenant mapping — use `AskUserQuestion` rather than proceeding with an assumption. The cost of a wrong assumption compounds across 20+ files, and the WorkOS Organization → Descope Tenant mapping in particular ripples into SSO, SCIM, RBAC, and domain routing. Uncertainty about architecture or intent is always worth a question.

**MCP over memory.** When the Descope MCP Server is available (confirmed in Part 1), use `docs_ask_question` to verify every SDK method name, option shape, and return type before writing it. Do not fall back to "verify the exact method name in the SDK type declarations" as a hedge — just verify it directly.

---

## 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 two sub-steps:

1. **Triage** — ask the questions needed to understand scope (migration questions go here since answers shape the plan)
2. **Codebase Analysis + Plan File** — scan the project, produce `MIGRATION-PLAN.md`, and pause for review

### Step 0: Triage (BLOCKING — requires `AskUserQuestion`)

**Use the `AskUserQuestion` tool to gather the information below. Do not infer answers
from memory, prior conversations, or assumptions — even if you think you know.**
The migration path differs based on these answers; getting them wrong wastes the user's
time and produces incorrect guidance.

Do not proceed to Step 0.5 until the user has answered.

**First `AskUserQuestion` call (up to 4 questions):**

1. **Backend language / framework** — Present the most likely options based on any cues
  in the conversation (e.g., Node.js, Go, Ruby, Python). The user can always
   pick "Other."
2. **Migration goal** — Full cut-over, incremental/phased migration, or just evaluating.
3. **Existing users and organizations** — Are they migrating an app with active users and
  organizations in WorkOS, staging/dev only, or starting fresh? This determines whether user
   and organization migration planning is needed (user export, org-to-tenant mapping, SCIM
   continuity, phased vs. big-bang cutover, forced re-login on cutover). 

**Second `AskUserQuestion` call — WorkOS feature usage (use `multiSelect: true`):**

1. **Which WorkOS features are in use?** Present the highest-impact categories:
  - **AuthKit** — WorkOS's hosted/embeddable login UI and session management (email/password, social login, passkeys, MFA, magic auth); which sign-in methods are enabled and whether the hosted or embedded flow is used.
  - **Organizations** — organization membership, organization switching, metadata, whether users can belong to multiple organizations.
  - **Enterprise SSO** — connections SAML, OIDC, or both; whether setup is handled by internal engineers or by customer admins; whether domain-based SSO routing is used.
  - **Directory Sync / SCIM** — which directories; group sync; group-to-role mapping; deprovisioning behavior; directory webhook handlers.
  - **Admin Portal / Widgets** — which customer-admin workflows are hosted by WorkOS today; whether the app generates portal links; whether Descope Widgets or the SSO Setup Suite can replace them.
  - **RBAC** — whether roles are global/environment or organization-scoped; where permission checks happen in code; whether roles/permissions are in tokens; whether IdP groups map to roles.
  - **FGA** — the authorization model (resources, relationships, privileges, hierarchy); where checks are performed. Flag as high complexity.
  - **Audit Logs** — whether logs are written to WorkOS, read back from WorkOS, shown to customers, or required for compliance.
  - **Radar** — whether it blocks, challenges, or only notifies about suspicious auth attempts; custom rules.
  - **Pipes** — which providers are connected; where connected-account tokens are used (AI agents, integrations, background jobs).
  - **Vault / Feature Flags** — flag as potentially outside the core Descope identity migration.
  - **MCP Auth / Connect** — flag for deeper review before implementation.
  - The user can add others via "Other."

After both calls, summarize findings and flag high-complexity items (Directory Sync/SCIM, FGA,
Pipes, MCP Auth/Connect, Vault) before proceeding to Step 0.5.

---

### Step 0.5: Engineer Review Checkpoint (BLOCKING — requires `AskUserQuestion`)

These questions surface blockers the framework doesn't expose. Ask even the ones you think
you know. Use `AskUserQuestion` before proceeding to codebase analysis.

Batch into calls of up to 4 questions. Skip questions that are clearly inapplicable given
Step 0 answers (e.g., skip user migration planning if they said they're starting fresh).

**Access and credentials**

- Do they have access to the Descope Console and a Project ID? (If not, see Step 1.5.)
- Do they need a Management Key? (Required for user CRUD, RBAC, ReBAC, tenant/SSO/SCIM configuration, Outbound Apps.)

**Codebase scope**

- Are there places in the app that read claims directly from the session token (e.g. `user.email`, `claims.organization_id`, `role`/`permissions`)? These need a JWT Template configured before they'll work.
- Does the app read WorkOS `organizationId`, `connectionId`, or `directoryId` in many places? The WorkOS Organization → Descope Tenant remap ripples through SSO, SCIM, RBAC, and membership checks — confirm the org model before writing code.
- Are there multiple services or microservices validating WorkOS tokens/sessions? Each needs to be updated to validate Descope JWTs.

**Deployment and risk**

- Do they have multiple environments (dev / staging / prod)? Each needs its own Descope project and Project ID.
- Is there a maintenance window, or does this need to be zero-downtime?

**User and organization migration** (if they indicated existing users/orgs in Step 0)

- How many users and organizations? This determines export approach and whether a phased cutover is warranted.
- Do they use passwords in AuthKit? Plan how password credentials carry over (export/import vs. reset vs. passwordless). Verify the current WorkOS user-export capability and the Descope import path before committing to an approach.
- Big-bang cutover or phased? Map each WorkOS Organization to a Descope Tenant first; user membership and tenant-scoped roles depend on it.
- **SCIM is a lifecycle system, not a one-time import.** If Directory Sync is enabled, enterprise directories will keep pushing create/update/suspend/delete events after cutover. A single user import is not enough — every SCIM/directory workflow must be re-pointed at Descope before cutover, or provisioning silently breaks.
- Are they aware that active WorkOS sessions will be invalidated on cutover unless a session-bridging approach is used? Plan for a forced re-login or phased rollout.

**Gaps to flag immediately** (don't ask — flag these proactively based on Step 0 answers)

- If they're using **Vault** or **Feature Flags**: these may have no direct Descope identity equivalent. Flag separately; do not pretend they are Descope SDK swaps. Ask whether they're in scope.
- If they're using **MCP Auth / Connect**: flag for deeper review before any implementation — likely maps to Descope Inbound Apps / OAuth app patterns, but needs dedicated mapping.
- If they're using **Audit Logs**: set up Descope's Audit Webhook Connector before cutover to avoid gaps in compliance/event logging. Missing this can break compliance visibility even though the app still runs.
- If they're using **Pipes / connected accounts**: connected third-party tokens may power integrations or background jobs. Identify provider connections and whether users must reconnect accounts.

**Console/Flow/Widget opportunities** (flag before codebase analysis, then ask):

- If the app uses the **WorkOS Admin Portal** or generates portal links: ask whether the SSO Setup Suite + Tenant Profile Widget replaces that workflow instead of rebuilding it as custom code. Do not default to building custom admin setup screens.
- If the app has a profile edit page or user management UI: ask whether a Descope Widget covers the use case.
- If the app has a separate MFA enrollment page: ask whether MFA should be integrated into the main sign-in Flow as a step or subflow instead (almost always cleaner in Descope).
- If any server-side code initiates SSO, generates emails, or runs logic during the auth journey: ask whether that logic can be a Flow step or Connector instead of server code.

Summarize any blockers and Console/Flow opportunities before proceeding to codebase analysis.

---

### Step 1: Codebase Analysis

Scan the codebase to map every auth touchpoint before writing the plan.

**Run these searches (adapt file extensions to the user's language):**

```bash
# Find all WorkOS / AuthKit import sites.
grep -rni "workos\|authkit" \
  --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \
  --include="*.mjs" --include="*.cjs" --include="*.py" --include="*.go" \
  --include="*.rb" --include="*.php" --include="*.java" --include="*.kt" \
  --include="*.cs" --include="*.ex" --include="*.exs" --include="*.rs" \
  --exclude-dir=node_modules --exclude-dir=.next --exclude-dir=dist --exclude-dir=venv \
  . 2>/dev/null

# Find all WorkOS env var references
grep -rn "WORKOS_\|workos\." \
  --include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" \
  --include="*.env*" --include="*.yml" --include="*.yaml" --include="Dockerfile" \
  --exclude-dir=node_modules --exclude-dir=.next \
  . 2>/dev/null

# Find WorkOS SDK surface + claim / token / org access patterns (things that may need a JWT Template or org→tenant remap)
grep -rn "workos.userManagement\|workos.organizations\|workos.sso\|workos.directorySync\|workos.auditLogs\|workos.fga\|workos.widgets\|workos.events\|workos.webhooks\|workos.pipes\|workos.portal\|workos.organizationDomains\|workos.featureFlags\|workos.types\|workos.mfa\|workos.authorization\|workos.vault\|organizationId\|organization_id\|orgId\|connectionId\|connection_id\|directoryId\|directory_id\|roleSlug\|permission" \
  --include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" \
  --exclude-dir=node_modules --exclude-dir=.next \
  . 2>/dev/null

# Find protected route / session access declarations
grep -rn "authkitMiddleware\|withAuth\|getUser\|ensureSignedIn\|getSignInUrl\|getSession\|isAuthenticated\|require_session\|@login_required\|authMiddleware" \
  --include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" \
  --exclude-dir=node_modules --exclude-dir=.next \
  . 2>/dev/null

# Find B2B / enterprise feature usage (SSO, SCIM, audit, admin portal, security)
grep -rn "scim\|saml\|sso\|auditLog\|audit_log\|adminPortal\|portalLink\|radar\|pipes" \
  --include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" \
  --exclude-dir=node_modules --exclude-dir=.next \
  . 2>/dev/null

# Check package.json / go.mod / requirements.txt for WorkOS dependencies
find . -maxdepth 3 \( -name "package.json" -o -name "go.mod" -o -name "requirements.txt" \) \
  ! -path "*/node_modules/*" -exec grep -l "workos" {} \;
```

For each hit, record:

- **File path and line** — where the change happens
- **What it does** — import, route protection, claim access, org/tenant read, SSO/SCIM config, webhook handler, logout handler, etc.
- **Complexity** — Low (drop-in replacement), Medium (logic rewrite), High (no equivalent)

Read `package.json` (or equivalent) for the exact framework version — this affects async
behavior (Next.js 15 vs 14) and SDK compatibility.

If the Descope Docs MCP is available, use `docs_search` or `docs_ask_question`
to verify current SDK method names for anything you plan to reference in the plan.

---

### Step 2: Write MIGRATION-PLAN.md

Write `MIGRATION-PLAN.md` to the working directory using the triage answers and codebase
analysis.

Two audiences: the engineer needs enough technical detail to execute; the PM or tech lead
needs scope, risk, and timeline without decoding jargon. Use plain English. Explain
technical terms on first use. Open each section with a sentence summarizing what it means
before presenting tables or evidence. Say what breaks if a risk is missed, not just that it
exists. Pair complexity labels with time estimates; skew toward the lower bound — SDK swaps and mechanical rewrites are usually faster than they look, and repetitive files in a group after the first go much faster. Group execution into phases so parallel vs. sequential work is clear.

The plan must include these sections, in this order:

#### Overview

2–3 sentences: what's being replaced, what replaces it, and the recommended approach with a
one-sentence rationale. Add one sentence on what doesn't change — user-facing login behavior,
sessions, organizations, and existing accounts are preserved.

Include a **Migration at a Glance** table:


|                                  |                                                                     |
| -------------------------------- | ------------------------------------------------------------------- |
| **Approach**                     | Full native migration                                               |
| **Files changing**               | N source files across N areas                                       |
| **Console setup**                | N configuration steps before launch                                 |
| **User impact**                  | No re-login required / Users will need to log in once after cutover |
| **Estimated engineering effort** | N–N hours                                                           |
| **Biggest risk**                 | One sentence naming the highest-complexity item                     |


---

#### What's Changing and Why

Prose (not a table) describing what each part of the system does today and what it does
after. Example:

> Today, WorkOS handles everything related to login: AuthKit shows the login UI, issues tokens
> and sealed sessions, validates them on every request, and routes enterprise users to the right
> SSO connection. After this migration, Descope takes over all of those responsibilities. The
> login UI becomes a Descope Flow embedded in the app. Session validation moves to the Descope
> SDK. WorkOS Organizations become Descope Tenants. The WorkOS API key, client ID, redirect URI,
> and cookie password are replaced by a single Descope Project ID.
>
> WorkOS features in use that need to carry over: [list in plain English, one clause each].

Tailor to triage findings.

---

#### Client SDK vs. Backend SDK: A Specific 1-to-1 Mapping

For every WorkOS touchpoint found in triage, produce a concrete, one-to-one mapping — WorkOS construct → the exact Descope SDK and method that replaces it —
and state explicitly whether that replacement runs in the **client SDK** or the **backend SDK**, and
why. Use this division of responsibility:

- **Client SDK** (`@descope/web-js-sdk`, `@descope/react-sdk`, `@descope/nextjs-sdk` client
  components, or the `<descope-wc>` web component) — everything the user's browser/app does:
  rendering the login/sign-up UI (a Descope Flow replaces AuthKit's hosted or redirect login),
  initiating authentication, holding the session on the client, refreshing the token, and reading
  the current user for UI purposes. This replaces AuthKit's UI, the redirect cycle, and any
  client-side session access. It uses only the public Project ID — never a Management Key.
- **Backend SDK** (`@descope/node-sdk`, `descope` (Python), `github.com/descope/go-sdk`, etc.) —
  everything the server does: validating the session JWT on every request (replacing WorkOS
  server-side `withAuth()` / middleware), checking roles and permissions, and — with a Management
  Key — all administrative operations done by ID (user and tenant CRUD, role/permission definitions,
  SSO/SCIM configuration, ReBAC). This replaces WorkOS server-side validation and every WorkOS
  Management API call.

For each file or area, name the WorkOS call, the Descope SDK that replaces it, which side it runs on,
and the reason (e.g. "session validation must stay server-side because the validation/Management key
cannot ship to the browser"). When one WorkOS feature spans both sides — for example AuthKit login
(now a client Flow) plus per-request `withAuth()` validation (now the backend SDK) — split it into
its client half and its backend half so the reader sees exactly what moves where, and why each piece
belongs on that side.

---

#### Auth Touchpoints: What the Code Analysis Found

Open with the scope count (e.g., "11 files across 4 areas"). Group by area, not file path.
Each group gets a sentence on what it does and what changes.

**Session handling (3 files)** — These files read and validate the current user's login
state. They'll be updated to use the Descope session SDK instead of WorkOS AuthKit. 


| File               | What it does today                                                            | What changes                                                                                              |
| ------------------ | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `lib/auth.ts:34`   | Returns WorkOS session via `withAuth()` with `user`, `organizationId`, `role` | Rewritten to return Descope `authInfo`; a thin adapter layer preserves the shape callers expect |
| `middleware.ts:12` | `authkitMiddleware()` blocks unauthenticated requests app-wide                | Updated to call Descope session validation; logic is identical, SDK call changes                          |


**Login / logout routes (2 files)** — These handle the AuthKit redirect-based login flow.
Descope replaces this with an embedded UI component (or hosted Flow); the redirect cycle changes.


| File                    | What it does today             | What changes                                                                                                  |
| ----------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| `app/callback/route.ts` | AuthKit OAuth callback handler | Deleted or rewritten — Descope handles this client-side; verify the replacement against the framework section |


Cover all functional groupings. End with: "Total: N files. Estimated code-change effort: N–N hours."

---

#### Feature Migration: WorkOS → Descope

For each WorkOS feature confirmed in triage, write a short paragraph: what it's trying to
accomplish, the best Descope approach for that goal, what's different, and what action is
required. The best approach may be a Flow, Widget, SSO Setup Suite, or Console configuration
rather than a direct SDK equivalent — reason about the intent, not just the API surface. Only
recommend SDK code when programmatic control is genuinely required. Example:

> **Multi-tenancy (WorkOS Organizations → Descope Tenants)**
> WorkOS Organizations group users by company and scope SSO, SCIM, roles, and domain policies.
> Descope has the same concept, called Tenants. Most code that handles organizations is
> management/admin code that passes a WorkOS `organizationId` to the API — that simply becomes a
> Descope **tenant ID** passed to `descopeClient.management.tenant.*` / `management.user.*` calls
> (load a tenant, create one, add/remove membership, scope roles). This is by-ID work, not token
> parsing. The only place a tenant shows up as a claim is request-time session reads: WorkOS's flat
> `organizationId` (from `withAuth()`) becomes Descope's nested `tenants` object (plus `dct` for the
> active tenant), which you read off the validated session — ideally via SDK helpers like
> `validateTenantRoles(authInfo, tenantId, [...])` rather than parsing claims by hand. Confirm the
> org→tenant mapping first, since it ripples into SSO, SCIM, and RBAC.
> **Effort: Medium (1–2 hours of code changes).** Confirm the data migration path for orgs first.

Only include confirmed features.

---

#### Before the Code Can Run: Required Configuration

Some Descope behavior is configured in the console, not in code. List every item that must
be set up before the app works, as checkboxes with a plain description of what it is, why
it's needed, and roughly how long it takes. Group into "Required before any testing" and
"Required before production":

**Required before any testing:**

- **Create a Descope project** — Takes 2 minutes. Produces a Project ID that replaces
all WorkOS credentials in the app's environment variables.
- **Create an authentication flow** — Descope uses a visual "flow" to define the login
experience (what methods are offered, in what order). The built-in `sign-up-or-in` flow
works for most apps and requires no customization to start.
- **Configure a user profile token template** — By default, Descope session tokens don't
include the user's name, email, or profile photo. This template needs to be configured so
the app can display user profile information. Without it, any part of the UI that shows the
user's name or email will show nothing after login. (~10 minutes)

**Required before production:**

- **Create tenants for each WorkOS Organization** — Descope Tenants must exist before
tenant-scoped code (SSO, roles, membership) will work.
- **Create roles** (or whatever the codebase references) — Descope roles must exist in the
console before code that assigns them will work.
- **Configure SSO connections per tenant** (or enable the SSO Setup Suite for self-serve) — SAML/OIDC connections need to be recreated.
- **Configure social login providers** (Google, GitHub, etc.) — OAuth credentials for
each provider need to be entered in the console. (~15 minutes per provider)
- (continue for each item found in analysis)

---

#### Environment Variables

Diff table with plain-English notes for each removal and addition:


| Remove                   | Add                              | Why                                                                                                                                 |
| ------------------------ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `WORKOS_API_KEY`         | —                                | WorkOS authenticates server-side calls with a secret API key. Descope uses a Project ID (+ optional Management Key) instead.        |
| `WORKOS_CLIENT_ID`       | —                                | WorkOS identifies the AuthKit client. Descope uses a Project ID.                                                                    |
| `WORKOS_REDIRECT_URI`    | —                                | AuthKit's OAuth callback URL, configured in console. Descope's embedded Flow doesn't require a server redirect URI in the same way. |
| `WORKOS_COOKIE_PASSWORD` | —                                | Used by AuthKit to encrypt/seal the session cookie. Descope issues a signed session JWT instead; no sealing password needed.        |
| —                        | `DESCOPE_PROJECT_ID`             | The single identifier for the Descope project. Replaces all of the above.                                                           |
| —                        | `NEXT_PUBLIC_DESCOPE_PROJECT_ID` | Same value, exposed to the browser for the login component (Next.js only).                                                          |
| —                        | `DESCOPE_MANAGEMENT_KEY`         | Only needed if the app manages users, roles, tenants, or SSO/SCIM server-side.                                                      |


Follow with: "Net change: 4 variables removed, 1–3 added. No secrets need to be rotated
on the WorkOS side — those credentials stop being used."

---

#### User & Organization Migration (only if existing users/orgs need to be migrated)

Prose strategy first, then steps. Start with: "X existing users across Y organizations need to be in Descope before cutover." Describe:

- **The plan**: whether this is big-bang (all users/orgs moved before cutover) or phased, and why
- **Org→tenant mapping**: each WorkOS Organization becomes a Descope Tenant; membership and tenant-scoped roles depend on this mapping being correct first
- **What users will experience**: will they need to log in again? Will anything look different?
- **The biggest dependency**: how password credentials carry over, and whether SCIM directories must be re-pointed at Descope (a continuing pipeline, not a one-time import)

End with a brief checklist of the migration steps at the level a PM can track:

- Export users and organizations from WorkOS
- Map each WorkOS Organization to a Descope Tenant
- Re-point SCIM/Directory Sync at Descope (if Directory Sync is in use)
- Do a dry run of the import against the Descope dev project
- Review dry-run output for errors
- Run live migration against staging, then production

---

#### Trade-offs and considerations

Things that could affect timeline, user experience, or scope. Write each in plain English
with three parts: **what it is**, **what breaks if it's ignored**, and **what to do**.
Format each as a named callout:

> **Consideration: Organization-to-tenant mapping affects almost every B2B feature**
> WorkOS Organizations should usually map to Descope Tenants. If this mapping is wrong, SSO, SCIM,
> roles, permissions, domain routing, and user membership checks may all break.
> **Action:** Confirm the organization model before writing migration code.

> **Consideration: SCIM is a lifecycle system, not just a user import**
> Directory Sync may create, update, suspend, and delete users or group memberships continuously.
> A one-time import is not enough if enterprise directories keep syncing after cutover.
> **Action:** Identify every SCIM/directory workflow and re-point it at Descope before cutover.

> **Consideration: Admin Portal workflows should not automatically become custom code**
> If the app uses the WorkOS Admin Portal, the Descope equivalent may be the SSO Setup Suite or a
> Widget rather than a custom settings page.
> **Action:** Ask whether tenant admins currently self-configure SSO/SCIM/domain verification.

> **Consideration: Audit logs can silently disappear**
> The app may keep working after migration even if audit logging is broken — creating compliance
> and enterprise-customer issues.
> **Action:** Set up Descope audit/event forwarding before production cutover.

> **Consideration: User profile data won't appear after login until a token template is configured**
> Descope session tokens don't include name, email, or profile photo by default. Any UI that
> displays user information will show blank values after migration until the token template is set
> up in the Descope console. This is a one-time configuration step, not a code change.
> **Action:** Configure the token template before running any tests. Estimated time: 10 minutes.

Include only applicable trade-offs and considerations.

---

#### Execution Plan

Open with one sentence: phases run in sequence; steps within a phase can run in parallel.
Then labeled phases, each with a time estimate:

---

**Phase 1 — Console Setup** (~30–60 minutes, no code required)
Can be done by any team member with Descope console access, in parallel with other work.

- Create Descope project, copy Project ID
- Create authentication flow (use the built-in `sign-up-or-in` to start)
- Configure user profile token template
- Create tenants for each WorkOS Organization (list actual orgs found)
- Create roles: (list actual roles found)
- Configure SSO connections per tenant or enable the SSO Setup Suite (if SSO in use)
- Configure social login providers: (list actual providers found)

**Phase 2 — Code Changes** (~X–Y hours, 1 engineer)
Work through files in the order listed. Run a compile check after each group.

- Update environment variables in `.env.example` and CI config (15 min)
- Rewrite session helper / `withAuth()` usage (30 min)
- Swap AuthKit provider/middleware for Descope equivalents (15 min)
- Update protected route files to use new session check (45 min)
- Repoint org handling to tenant IDs — management calls pass a `tenantId`; request-time session reads use `tenants`/`dct` (varies)
- Update logout — two-step logout (15 min)
- Compile check and fix any type errors before proceeding

**Phase 3 — User & Organization Migration** (~1–2 hours, includes dry run)
Run against dev/staging first. Do not run against production until Phase 4 passes.

- (steps from user & organization migration section above)

**Phase 4 — Testing** (~30–45 minutes)

- Compile passes with zero errors
- Server starts, no crashes on startup
- Unauthenticated routes redirect to login correctly
- Login flow completes, user profile data appears (confirms token template is working)
- Tenant/SSO routing works for at least one organization
- Logout invalidates session

**Phase 5 — Production Cutover**

- (cutover-specific steps based on their strategy — maintenance window, phased rollout, SCIM re-point, etc.)

---

Total estimated engineering effort: **N–N hours** across N engineers.
Blocking dependencies: (list anything on the critical path — console access, SCIM re-point, etc.)

---

After writing `MIGRATION-PLAN.md`, **stop and tell the user:**

> `MIGRATION-PLAN.md` has been written to your working directory. It maps every auth
> touchpoint found, lists what needs Console setup before the first test, and calls out
> trade-offs and considerations that could affect the timeline.
>
> Take a look before we start making changes. When you're ready to proceed, say so.

Do not proceed to Part 3 unless 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.

**Step 3.0 — Create `MIGRATION-STATE.md` before touching any code.**

Write `MIGRATION-STATE.md` to the working directory from the template below. It's 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 14, Express + React]
- Language: [TypeScript / Python / Go]
- Package manager: [npm / yarn / pnpm / pip / etc.]
- Migration path: [Path A: OIDC compat / Path B: Full native]
- Migration goal: [Full cutover / Phased / Evaluating]

## Triage Answers
- Existing users: [Yes — N users / No — greenfield]
- Existing organizations: [Yes — N orgs → tenants / No]
- Password migration needed: [Yes / No]
- WorkOS features in use: [comma-separated list]
- Multiple environments: [Yes: dev/staging/prod / No]
- Zero-downtime required: [Yes / No]

## Files Inventory
_All files that need to change. Update status after each step._

| File | Change | Status |
|---|---|---|
| `app/callback/route.ts` | Delete/rewrite | ⬜ Pending |
| `lib/auth.ts` | Rewrite session helper | ⬜ Pending |
| `middleware.ts` | Update session check | ⬜ Pending |

## Console Setup Checklist
- [ ] Descope project created — Project ID: (fill in when done)
- [ ] JWT template configured
- [ ] Tenants created for each WorkOS Organization: (list)
- [ ] Roles created: (list roles)
- [ ] SSO connections / SSO Setup Suite configured: (list)
- [ ] Social providers configured: (list providers)

## Decisions Log
_Non-obvious decisions made during migration — preserves rationale if context is lost._

_(none yet)_

## Current Phase
Phase 1 — Console Setup (not started)

## Next Action
Complete console setup per MIGRATION-PLAN.md before making any code changes.

## Blockers
_(none)_
```

---

**Rule 1 — Re-read before every turn.**

At the start of every execution turn, re-read `MIGRATION-PLAN.md` and `MIGRATION-STATE.md`
before writing any code or making any decision.

**Rule 2 — Verify context before every code change.**

If the framework, migration path, triage answers, or next step aren't clear from the
conversation, re-read both files before proceeding. Then output a context line:

> `Migration context: Next.js 14 · Path B · Phase 2, step 3/8 · Next: rewrite lib/auth.ts`

If this line can't be filled in accurately, re-read the files first.

**Rule 3 — Update `MIGRATION-STATE.md` immediately after each step.**

Mark the file done in the Files Inventory, update "Current Phase" and "Next Action", and
append any non-obvious decision to the Decisions Log. Do this before the next step.

---

## Pre-Generation Protocol (apply before writing any code)

Run before generating any import, wrapper type, or helper. 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. This is faster and more reliable than reading type declarations. Do not write a method name and add a hedge like "verify the exact name" — just 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 exported name and signature. For Go, run `go doc`. For Python, check the SDK stubs.

**Prefer local `node_modules/` over GitHub** when reading type declarations. Installed packages reflect the exact version in use. If the Descope package isn't installed yet, install it first, then read local type declarations. Only fall back to GitHub if the package can't be installed in the current environment.

This applies to **every SDK call you write**, not just the first import. Field names on
option objects, hook return shapes (`useDescope()` returns the SDK directly, not `{ sdk }`),
and subpath exports (`/client` vs root) differ just as often.

**1a. After rewriting any module, grep for remaining imports of the removed package.**

```bash
grep -r "from '@workos-inc/" --include="*.ts" --include="*.tsx" .
```

Add remaining hits to the work list.

**2. Derive wrapper types from the actual return type.**
Read the function's declared return type and build the wrapper to match. WorkOS's field
names, nesting, and flags differ — don't infer from them.

**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` (or `go.mod`, `requirements.txt`) first.

**4. When making a helper async, propagate to all callers immediately.**
In TypeScript, `async` on a shared utility silently breaks callers that omit `await`. Grep
for all call sites of the changed function and update them in the same pass. The cascade can
span 10–20 files.

**5. Verify published package versions before writing to `package.json` or running `npm install`.**
Don't reuse WorkOS's version number or rely on training data for versions. Before writing any
install command:

```bash
npm view @descope/node-sdk version
npm view @descope/nextjs-sdk version
```

If npm is unavailable, leave the version as `"latest"` and flag it.

---

## Step 1.5: Descope Project Setup & Console Configuration

Several steps require Descope Console setup that can't be done in code. The app compiles
without them but won't work at runtime.

Use `AskUserQuestion` to ask whether they already have a Project ID and working Flow. If
yes, skip to verifying items 5–7 — these 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 top-left project selector and under **Project → General**. It starts with `P` (e.g. `P2abc123...`).
- For Next.js client-side code, this becomes `NEXT_PUBLIC_DESCOPE_PROJECT_ID`. For all server-side SDKs, it's `DESCOPE_PROJECT_ID`.

### 2. Get a Management Key (if needed)

Required for: user management API, role/permission management, tenant operations, SSO/SCIM
configuration, ReBAC (FGA), Outbound Apps. If the app does any server-side user, tenant, SSO,
or SCIM management, they need this.

- Console → **Company → Management Keys → + Management Key**
- Store as `DESCOPE_MANAGEMENT_KEY`. Treat like a secret — never exp

…(truncated)
