Migrating Azure AD B2C users without password hashes
Azure AD B2C will not give you password hashes. Microsoft Graph's passwordProfile is a write
path — you set a password on an account you are creating — and there is no property, endpoint
or support process that reads one back. So moving users to Keycloak means moving profiles,
which is easy, and then dealing with credentials, which is the whole project.
There are three patterns, and most migrations use two of them. Broker B2C as an OIDC identity provider and let users keep signing in through it while applications move. Validate the password at first login against B2C and store it locally. Send a reset to whoever is left at the cutover date.
The received wisdom — the pattern that works for Auth0 and Cognito — is that the second one is the default. For B2C it is not, and the reason is in Microsoft's own documentation: the only endpoint that can validate a B2C password from your code is the ROPC endpoint, which is documented as local-accounts-only and explicitly unsupported server-to-server. Start from brokering instead.
Everything below was run against Keycloak 26.8.1 in start-dev; the Java compiles against
26.8.1. Every HTTP status and response body is copied from an actual run.