Microsoft has set a sunset path for Azure AD B2C. Entra External ID is the named successor for external identity scenarios. If your Power Pages site uses B2C today, you are on a migration clock. The Power Pages authentication wiring is similar between the two products, but the contact-record linkage rules are not, and that is where migrations go wrong.
The two identity products
- Azure AD B2C: separate tenant, custom policies, distinct from your workforce Entra tenant. Used for years for portal identity.
- Entra External ID: external identity hosted within the workforce Entra tenant as an external collaboration scope. Different config surface, different token shape, different price.
The migration is not lift-and-shift. It is reconfigure-and-relink.
What stays the same
- The OpenID Connect protocol. Power Pages still consumes an OIDC IdP.
- The contact-to-identity link via the
mspp_externalidentitytable or theContact.AuthenticationTypeandContact.Usernamecolumns. - The Liquid
userobject for templating.
What changes
- The tenant scope. External ID lives in your workforce tenant; B2C had its own tenant.
- The token claim shape. The
subclaim and tenant claims differ. - User flows vs custom policies. External ID uses user flows; B2C had both. Migration from a custom-policy B2C is more work than migration from a user-flow B2C.
- Branding and self-service. External ID’s UX surface is different. Pixel will want to revalidate.
The migration plan
A staged plan with parallel run:
- Provision External ID in your workforce tenant. Configure a user flow with email + password and any social providers you support.
- Configure Power Pages with a new OIDC IdP record pointing to External ID. Keep the B2C IdP record active.
- Allow users to sign in with either provider for a transition period.
- Bridge the identity link: when a user authenticates via External ID for the first time, look up the existing contact by email and write a new
mspp_externalidentityrow linking the contact to the new identity. - Notify users to re-enroll via External ID. Track conversion.
- Deprecate B2C after the conversion threshold.
Provision External ID
Within the workforce tenant, External ID surfaces as an “External Identities” experience. Create a user flow with the providers you need. Capture the application registration’s client ID, client secret, and the OIDC metadata URL.
{
"userFlow": "B2C_1A_SignInSignUp",
"providers": ["EmailWithPassword", "Google", "Microsoft"],
"claims": ["sub", "email", "given_name", "family_name"],
"tokenLifetime": 60
}
Wire Power Pages
In Power Pages, add an OIDC IdP. The settings:
- Authority: the External ID metadata URL.
- ClientId / ClientSecret: from the app registration.
- RedirectUri: the Power Pages site’s
/signin-oidcendpoint. - Scope:
openid profile email. - IssuerFilter: pin to the External ID issuer to prevent token confusion.
The site settings:
Authentication/OpenIdConnect/ExternalID/Authority = https://<tenant>.ciamlogin.com/<tenant-id>/v2.0
Authentication/OpenIdConnect/ExternalID/ClientId = <client-id>
Authentication/OpenIdConnect/ExternalID/ClientSecret = <secret>
Authentication/OpenIdConnect/ExternalID/RedirectUri = https://<your-site>/signin-oidc
Authentication/OpenIdConnect/ExternalID/Scope = openid profile email
Authentication/OpenIdConnect/ExternalID/CallbackPath = /signin-oidc
Authentication/OpenIdConnect/ExternalID/Issuer = https://<tenant-id>.ciamlogin.com/<tenant-id>/v2.0/
Test with a fresh user. Validate that the contact is created and linked.
The bridge logic
The hard part. When a user authenticates via External ID for the first time, Power Pages will (by default) create a new contact. You do not want a new contact if one already exists from the B2C era. Add a custom Liquid snippet or a pre-authentication Power Automate flow to:
- Look up an existing contact by the email claim.
- If found and unlinked to External ID, attach the External ID identity as a new
mspp_externalidentityrow. - If found and already linked to a different External ID identity, raise a conflict — likely a user enrolled twice.
- If not found, allow the new contact creation.
// Custom JavaScript in the registration template
const email = portalUser.claims.email;
const existing = await fetch(`/_api/contacts?$filter=emailaddress1 eq '${email}'`);
if (existing.value.length === 1) {
await fetch('/_api/mspp_externalidentities', {
method: 'POST',
body: JSON.stringify({
'mspp_identityprovidername': 'ExternalID',
'mspp_username': portalUser.claims.sub,
'[email protected]': `/contacts(${existing.value[0].contactid})`
})
});
}
Validate the bridge against test cases: user with only B2C link, user with no identity link, user with email collision, user already linked.
What about MFA
External ID supports MFA via the same Entra MFA features used for workforce. Configure at the user-flow level. The user experience differs from B2C: External ID surfaces the Entra MFA prompt, which has a different look. Communicate this to users before cutover or they will report it as broken.
See also
Power Pages anonymous access risks — the bridge logic must not bypass anonymous access controls during the unauthenticated lookup step. Use a server-side proxy with a service account, not the anonymous user, to do the email-by-email lookup. (Referencing the security role piece for the broader access-control mental model.)
Pixel notes
The External ID sign-in surface is hosted by Microsoft and themable. Spend a day on the theme — fonts, logo, colors, error copy. The default look is generic and will land for users as “this is not the company I am signing into”. A small branding investment cuts the support tickets in half.
Forge notes
The OIDC token from External ID includes a tid (tenant id) claim. The IssuerFilter setting must include it. If you skip the filter, your portal will accept tokens from any External ID tenant Microsoft chooses to introduce in the future — a subtle confusion attack vector.
Bottom line
- B2C is winding down; External ID is the named successor.
- Power Pages supports both via OIDC; the IdP record swap is straightforward.
- The contact-link bridge is the hard part. Build it server-side with a service identity.
- Run both providers in parallel during the conversion window.
- Validate token issuer filters; do not accept tokens from arbitrary External ID tenants.