Frontegg Migration Guide

Migration Skill Available

Want a faster, guided migration? The Frontegg to Descope Migration Skill in descope/skills inventories the Frontegg features and authentication touchpoints in your application, then produces a migration plan before making code changes.

This guide covers how to migrate your Frontegg users, accounts, roles, and permissions to Descope, and how to move the parts of Frontegg that live outside the user store: hosted login, the self-service admin portal, SSO connections, and backend token validation.

You can migrate from Frontegg to Descope in two main ways:

  • Full Migration: You export users and accounts from the Frontegg Management API, import them into Descope, and then run only on Descope. (Most common)
  • JIT Migration: Descope creates each user the first time that user signs in, so you do not run a bulk export. JIT migration is the only path that keeps existing passwords.

You can combine either path with SSO migration for tenant SSO connections. Before you start, read the migration strategy page for the decisions every migration shares, such as cutover timing and which settings to recreate.

Frontegg and Descope Terminology

Frontegg is a B2B identity platform, so most of its objects have a direct Descope equivalent. The main differences are in how Frontegg groups configuration and in features, such as entitlements, that Descope models with roles and attributes.

Frontegg ConceptDescope EquivalentDescription
Workspace and EnvironmentProjectEach Frontegg environment (for example, development and production) maps to its own Descope project.
UserUserFrontegg uses email as the primary identifier and links login methods that share an email.
Account (tenant)TenantFrontegg Accounts map to Descope Tenants.
Sub-accountSub-tenantFrontegg account hierarchies map to Descope sub-tenants.
Role and PermissionRole and PermissionFrontegg roles map to Descope roles. Frontegg puts the role key in tokens, so use the key as the Descope role name.
Entitlements (plans and features)Roles, Permissions, or Custom AttributesDescope has no plan or feature object. You can model a plan as a role that carries the feature's permissions, or store the plan on the tenant as a custom attribute.
Hosted Login and Login BoxFlowsThe Frontegg login box maps to a Descope Flow, which you can host on Descope or embed in your application.
Admin Portal (self-service)Widgets and SSO Setup SuiteEnd-customer user, role, and profile management map to Descope Widgets. Self-service SSO setup maps to the SSO Setup Suite.
PrehooksFlow actions and ConnectorsLogic that Frontegg runs before sign-up or sign-in moves into a Flow step, often through a connector.
Custom JWT claimsJWT TemplatesClaims that your application reads from the Frontegg token move into a JWT Template.
API tokens and client credentialsAccess Keys or Inbound AppsMachine-to-machine credentials map to Access Keys or Inbound Apps.

Full Migration

In a full migration, you copy your Frontegg data into Descope and then switch your application to Descope.

Passwords cannot be exported from Frontegg

Frontegg does not export password hashes, so a full migration moves users without their passwords. After the import, you can move users to a passwordless method (magic link, OTP, or passkeys), or require a password reset on first sign-in. To keep passwords, add JIT migration to your Flow during the cutover.

Descope must create objects in dependency order, because a user cannot reference a tenant or role that does not exist yet. The order is tenants, then permissions, then roles, then users.

FronteggManagement APIYour migration scriptwritten by you or an AI agentDescopeManagement API1. POST /auth/vendor2. vendor token3. GET accounts, permissions, roles, users4. GET user roles, one account at a time5. map role IDs to keys, build userTenants6. create tenants, permissions, roles7. batch create users

The script creates objects in dependency order, so every tenant and role exists before a user references it. Users import without passwords, because Frontegg does not export password hashes.

Let an AI agent write the migration script

An AI agent connected to the Descope MCP Server can write the export and import scripts for your Frontegg setup, mapped to your own attributes, tenants, and roles. Descope's open-source migration tool also includes a Frontegg module that you can run as it is or use as a template.

Prerequisites

You need credentials for both systems before you export anything.

  • Frontegg: You need the Client ID and API key of the environment you are migrating, from Keys & domains in the Frontegg portal. You also need the API gateway of your Frontegg region.
  • Descope: You need your Project ID and a Management Key.

Frontegg runs a separate API gateway in each region. Use the gateway that matches your account.

RegionAPI gateway
EUhttps://api.frontegg.com
UShttps://api.us.frontegg.com
CAhttps://api.ca.frontegg.com
AUhttps://api.au.frontegg.com

1. Export Data from Frontegg

The Frontegg Management API authenticates with a short-lived vendor token. Your script requests the token with the Client ID and API key, then sends it as a bearer token on every export call.

# Get a vendor token. The response contains "token" and "expiresIn" (seconds).
curl -X POST "https://api.frontegg.com/auth/vendor" \
  -H "Content-Type: application/json" \
  -d '{"clientId": "<FRONTEGG_CLIENT_ID>", "secret": "<FRONTEGG_API_KEY>"}'

With the token, your script reads each object type from these endpoints. See the Frontegg API reference for the full response shapes.

DataEndpointNotes
AccountsGET /tenants/resources/tenants/v2Paginated.
PermissionsGET /identity/resources/permissions/v1Returns a plain array.
RolesGET /identity/resources/roles/v1Returns a plain array. Each role lists its permission IDs.
UsersGET /identity/resources/users/v3Paginated. Without a frontegg-tenant-id header, the call returns every user in the environment.
User rolesGET /identity/resources/users/v3/roles?ids=<userId>&ids=<userId>Requires the frontegg-tenant-id header. Returns the role IDs of each user in that account.
SSO configurationsGET /team/resources/sso/v1/configurationsRequires the frontegg-tenant-id header. Needed only for SSO migration.

The paginated endpoints accept _limit (at most 200) and _offset. In these APIs, _offset is a page number that starts at 0, not a record offset. Your script should request pages 0, 1, 2, and so on until it reaches _metadata.totalPages. A script that adds 200 to _offset on each call skips most of the data.

Note

The users list returns each user's tenants array with empty roles. Your script must read role assignments from the user roles endpoint, one account at a time, or users import without their roles.

2. Map Frontegg Data to Descope

Each Frontegg object maps to a Descope object that the Management API can create. Create the tenants first with the Frontegg account ID as the Descope tenant ID, so user memberships can reference them without a lookup table.

Frontegg fieldDescope fieldNotes
emailloginId and emailUse the email as the login ID. Fall back to the Frontegg id for users without an email.
verifiedverifiedEmailSet only for users whose email Frontegg marked as verified.
namenameFrontegg can store LDAP-style CN= values in name. Skip those values.
phoneNumberphoneDescope requires E.164 format. Drop or fix numbers that do not match.
profilePictureUrlpicture
tenants[].tenantId with its role IDsuserTenants[] with tenantId and roleNamesResolve each role ID to the role key you used as the Descope role name.
isLockedstatus: "disabled"
id, metadata, mfaEnrolled, providerCustom attributesKeep the Frontegg id so you can trace each user back to Frontegg. metadata is a JSON string.

Define each custom attribute in Descope before the import. Also set a freshlyMigrated custom attribute to true on every imported user. During the cutover, your Flow uses the attribute to check those users' passwords with Frontegg. After the transition, the Flow uses it to route them to a password reset or passwordless enrollment.

3. Import into Descope

Descope can create users one at a time with Create User, or in groups with Batch Create Users. For a large user base, use the batch endpoint and follow the user management rate limits. The field names in the mapping table match the Batch Create Users API reference. The user JSON formatting guide uses different field names and applies only to Console imports.

Run the import against a development project first, and compare the record counts with your Frontegg export. Then repeat the import against your production project.

4. Cut Over

The cutover with the least risk switches your application to Descope in one step and keeps Frontegg available behind the Flow for a transition period. With JIT migration in your sign-in Flow, Descope checks passwords with Frontegg for users it cannot sign in yet. You therefore do not need to freeze Frontegg or run a final export before the switch.

  1. Add the Generic HTTP Connector to your sign-in Flow. Use a condition that sends new users and freshlyMigrated users to Frontegg.
  2. Switch your application from the Frontegg SDK to the Descope SDK.
  3. Keep Frontegg running for the transition period, then turn it off.

During the transition, each sign-in follows one of three paths:

  • Users that Descope can sign in: These users sign in with Descope directly, and the Flow does not call Frontegg.
  • Imported users without a password: The Flow checks the password with Frontegg. These users already exist in Descope, so the Sign Up / Password action fails for them. The Flow signs the user in with OTP or magic link instead, stores the password with the Update Password action, and clears freshlyMigrated. The user keeps the same password, and verifies their email or phone once.
  • Users who signed up in Frontegg after your export: These users are not in Descope yet. The Flow checks the password with Frontegg, and the Sign Up / Password action creates the user with that password.

You decide how long the transition lasts. To keep passwords for most active users, we recommend keeping Frontegg on for at least a few months. After you turn Frontegg off, users who did not sign in during the transition verify their email or phone, and then sign in with a passwordless method or reset their password.

A few changes still need a plan, because JIT migration does not cover them:

  • Role and account changes: The connector creates missing users but does not update the roles of users you already imported. Re-sync accounts and role assignments from Frontegg once, right after the switch, to catch changes that admins made after your export.
  • Existing Frontegg sessions: Users with an active Frontegg session sign in again after the switch, unless your backend accepts both tokens for a period, as described in Session Validation Strategy.
  • Older mobile app versions: An app version that still uses the Frontegg SDK keeps sending users to Frontegg until they update. JIT migration creates those users in Descope when they sign in with a newer version.

Frontegg apps use either hosted login, where Frontegg redirects the user to a Frontegg-hosted page, or an embedded login box. A hosted-login app maps most directly to a Descope-hosted Flow that your app reaches through OIDC. An embedded-login app maps to the Descope components that render a Flow inside your page.

JIT Migration

Note

For JIT migration, keep Frontegg running for the transition period you choose. To keep passwords for most active users, we recommend at least a few months.

With Just-In-Time (JIT) migration, Descope creates each user when that user signs in, so the migration happens gradually and without downtime. You can check credentials against Frontegg in two ways, depending on whether users must keep their passwords.

Using the Generic HTTP Connector

Use this approach to keep passwords working. On first sign-in, your Flow sends the user's email and password to Frontegg, and Frontegg checks them.

Userbrowser or appDescope FlowGeneric HTTP ConnectorFrontegglogin domain1. email and password2. condition: user not in Descope yet3. POST /identity/resources/auth/v1/user4. Frontegg user token5. Sign Up / Password: create user, set password6. Descope session

Frontegg checks the password, and Descope stores the same password when it creates the user. The user does not notice the migration.

  1. The user enters an email and password in your Descope Flow.
  2. A Generic HTTP Connector calls the Frontegg "Authenticate user with password" API (POST /identity/resources/auth/v1/user) on your Frontegg login domain.
  3. If Frontegg accepts the credentials, the Flow creates the user in Descope, sets the password, and starts a Descope session.
  4. On later sign-ins, Descope checks the password itself, and Frontegg is not involved.

Frontegg returns a user token rather than a user profile. Your Flow can read the user ID and account from that token, or call the Frontegg users API for the rest of the profile.

Using Frontegg as a Custom OIDC Provider

Use this approach if you are moving users to passwordless sign-in, or if a password reset on first sign-in is acceptable. Users sign in through Frontegg's hosted login once, and Descope creates them from the returned ID token.

Userbrowser or appDescope Flowcustom OAuth providerFrontegghosted login1. start sign-in2. OAuth redirect to Frontegg3. user signs in, MFA included4. authorization code, then ID token5. create user from the ID token claims6. Descope session

Frontegg authenticates the user, and Descope creates the user from the claims it receives. Descope does not get the password, so the user needs a new sign-in method for later sign-ins.

  1. Add Frontegg as a custom OAuth provider in Descope. Use the client ID, client secret, and endpoints from your Frontegg domain's OpenID configuration.
  2. Add a Sign Up or In / OAuth action to your Flow that sends users to Frontegg.
  3. Map the ID token claims to Descope user attributes. Descope creates the user and starts a Descope session.

After Descope has created a user, a condition in your Flow can route that user to Descope-native sign-in, such as passkeys or magic link, so the user no longer goes through Frontegg.

SSO Migration

If your Frontegg accounts use SAML or OIDC SSO, you can move each connection to the matching Descope tenant so customer admins do not have to set up their IdP again. For the full process, including tenant setup, DNS redirect, and testing, see SSO Migration.

Frontegg stores less of each connection than Descope needs, so plan to complete some fields by hand:

  • SAML: Frontegg does not store the IdP entity ID. You can often derive the entity ID from the IdP's SSO URL (for example, Okta and Microsoft Entra ID use predictable formats). For other IdPs, you must enter it in the tenant's SSO settings.
  • OIDC: Frontegg stores only the authorization endpoint. You can read the issuer, token, user info, and JWKS URLs from the IdP's /.well-known/openid-configuration document.

Session Validation Strategy

Whether you choose a full migration or a JIT migration, some users will still have Frontegg sessions after you start issuing Descope sessions. Your backend should accept both token types during the transition:

  • Descope session tokens: Validate these for users who already signed in through Descope.
  • Frontegg tokens: Validate these for users who still have an active Frontegg session.

Your backend can read the unverified iss claim to choose a validator. Each validator must then check the token signature against that provider's keys before your backend trusts any claim, because the iss claim alone is not proof of where a token came from. For the pattern, see dual token validation.

Descope tokens carry tenant data in different claims than Frontegg tokens. Code that reads tenantId or tenantIds from a Frontegg token should read dct (the current tenant) or tenants from a Descope token. If your code depends on Frontegg claim names, you can recreate them in a JWT Template.

Post-Migration Verification

After the cutover, check that the data, sign-in, and authorization behave as they did in Frontegg.

  • Compare Frontegg user and account counts with Descope user and tenant counts, and resolve every failed record.
  • Confirm that users in more than one account have every expected tenant membership and role.
  • Confirm that every locked Frontegg user has the disabled status in Descope.
  • Test every sign-in method, including password reset or passwordless enrollment for freshlyMigrated users.
  • Test every migrated SSO connection with a real sign-in from the customer's IdP.
  • Confirm that your APIs reject expired, invalid, and wrong-issuer tokens.
  • Search your code and configuration for leftover Frontegg SDK imports, FRONTEGG_* environment variables, and Frontegg claim names.

For the settings that sit around your users, such as password policy, email providers, and audit streaming, see the migration strategy page.

Was this helpful?

On this page