Blog · Guides

Leaving Azure AD B2C: moving users, passwords and custom policies to Casdoor

Azure AD B2C has been closed to new customers since May 2025. How to export B2C users through Microsoft Graph, what Casdoor's Azure AD syncer moves, and how to handle passwords and custom policies.

Casdoor Team · October 31, 2026 · 4 min read

This guide is written by the team that builds Casdoor and describes the standards as published (listed under Sources), with notes on how Casdoor implements them as of October 31, 2026. Spotted a mistake? Tell us.

Azure AD B2C stopped being sold to new customers on May 1, 2025. The P2 tier was retired on March 15, 2026, and Microsoft says it will support existing tenants until at least May 2030. Its stated successor is Microsoft Entra External ID.

If you are leaving B2C — for cost, for data residency, or because you want the same protocols without a per-MAU bill — the migration has three parts: users, passwords, and custom policies. Only the first one is easy.

What B2C lets you export

B2C user accounts are readable through Microsoft Graph: list users with GET /v1.0/users, page through the results, and read the profile fields your application needs.

Microsoft's own user migration guide describes two approaches, and both are about moving into B2C, which is exactly why they are useful to read in reverse:

  • Pre-migration requires access to plaintext or decryptable credentials. That is the only case where passwords move in a straightforward way.
  • Seamless migration creates the accounts with random passwords, then validates each user against the legacy store on first sign-in through a REST API and writes the password at that moment.

For a migration out of B2C, the second approach tells you what to expect: password hashes are not exportable through Graph. Any plan that assumes "export users with passwords" will fail at the first test.

What Casdoor's Azure AD syncer moves

Casdoor has an Azure AD syncer that reads users from Microsoft Graph with the client-credentials flow:

  • Host: the tenant ID or tenant domain (for a B2C tenant, the contoso.onmicrosoft.com domain or its tenant ID).
  • User field: the application (client) ID of an app registered in that tenant.
  • Password field: the client secret.
  • It calls https://graph.microsoft.com/v1.0/users?$top=999 and follows the @odata.nextLink pagination.

The fields it maps include user principal name, display name, given name, surname, mail, mobile phone, job title, office location, preferred language and account-enabled state. The syncer is read-only, and group membership is not synced in the current implementation.

To set it up, register an app in the B2C tenant, grant it the Microsoft Graph application permission User.Read.All, and create a client secret. Then create a syncer in Casdoor with type Azure AD and the three values above. See the Azure AD syncer docs.

Passwords: plan for a reset

Because B2C does not expose password hashes, the realistic options are the same as any other SaaS identity provider:

  1. Reset campaign. Import the profiles and email every user a reset link. Predictable, with a support spike.
  2. Reset at next sign-in. Flag imported users and force the reset when they next authenticate.
  3. Validate against the old tenant at first sign-in. This is Microsoft's seamless pattern; on the Casdoor side it is custom work, so budget for it only if a mass reset is unacceptable.

For B2C tenants that use social providers heavily, a large share of users never had a local password to begin with. Those users can keep signing in with their social account once the provider is configured in Casdoor; nothing needs to be reset.

Custom policies are the real project

B2C's custom policies are XML trust frameworks: claims providers, technical profiles, user journeys. They do not export to any other product, including Entra External ID. Every policy has to be rebuilt as configuration in the new system, and the work is proportional to how much logic lives there:

  • Sign-up and sign-in flows, including attribute collection and validation.
  • Profile editing and password reset flows.
  • MFA steps and conditional access.
  • REST API calls to your own services (the "validate at first login" pattern, for example).
  • Claims transformation and token enrichment.

Casdoor covers the common cases through its login, registration, reset and MFA settings, and its application and organization model. Anything that depended on a custom claim transformation becomes application-side work. Inventory the policies before you scope the migration; this is where most of the effort hides.

What else does not migrate

  • Applications. Each B2C app registration becomes a Casdoor application with new client IDs and the same redirect URIs.
  • Identity providers. Recreate Google, Facebook, Apple and any SAML/OIDC connections in Casdoor.
  • Custom attributes. B2C allows 100 custom attributes per user; map them to Casdoor user properties and decide which ones actually matter.
  • MFA enrollments and sessions. Users re-enroll and sign in again.

A cutover plan

  1. Inventory users, identity providers, custom policies and applications.
  2. Register the Graph app in the B2C tenant and test the syncer with a small group.
  3. Decide the password strategy and test it on the sample.
  4. Rebuild one application and run it against Casdoor in a test environment.
  5. Migrate in cohorts, keeping B2C running as the source of truth until the last cohort moves.
  6. Keep B2C read-only for the rollback window, then decommission. The support window runs to 2030, so there is no deadline pressure — but there is also no reason to keep paying for two systems.

Why Casdoor

Casdoor covers what B2C customers usually need: OIDC, SAML 2.0, CAS, SCIM, social providers, MFA and passkeys, organizations and roles, with a Graph-style syncer for the data move. It is Apache-2.0 and self-hostable; the hosted version starts at $9 per month with unlimited MAU and no per-user or per-connection fees.

Related reading: Azure AD B2C alternatives and the Casdoor vs Entra External ID comparison.