I have started using custom policies for our B2C Tenant and while doing so I had the requirement that the email confirmation has to be done on a separate page. As such, I added an extra step after the signup form on which I implemented the email confirmation UI component. The user is only written to B2C after that email confirmation is done. My problem is now, that if I add the ValidationTechnicalProfile "AAD-UserWriteUsingLogonEmail" right in the signup form with all the fields it creates the user just as intended, but if I wait with it until the second journey step where I confirm the email address, the user is created with all intended data, but is always disabled. Even if I add the accountEnabled variable manually and set it to true, the user is still disabled. When debugging in Azure insights, the claim for accountEnabled is always true in all steps, but the audit log on the Azure platform for creating the user shows the claim as false in the modified properties tab. Is there anything that B2C requires for it to not automatically disable the user?
The first step that gathers user data:
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmailCustom">
<DisplayName>Email signup</DisplayName>
<Protocol
Name="Proprietary"
Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
/>
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="language.button_continue">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="GetCurrentDateTime" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim
ClaimTypeReferenceId="extension_termsOfUseConsentChoice"
DefaultValue="AgreeToTermsOfUseConsentNo"
/>
</InputClaims>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="email" Required="true" />
<DisplayClaim ClaimTypeReferenceId="newPassword" Required="true" />
<DisplayClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<DisplayClaim ClaimTypeReferenceId="givenName" Required="true" />
<DisplayClaim ClaimTypeReferenceId="surName" Required="true" />
<DisplayClaim ClaimTypeReferenceId="extension_companyName" />
<DisplayClaim ClaimTypeReferenceId="country" />
<DisplayClaim ClaimTypeReferenceId="city" />
<DisplayClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" Required="true" />
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="newUser" />
<!-- Optional claims, to be collected from the user -->
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surName" />
<OutputClaim ClaimTypeReferenceId="extension_companyName" />
<OutputClaim ClaimTypeReferenceId="country" />
<OutputClaim ClaimTypeReferenceId="city" />
<OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" Required="true" />
</OutputClaims>
</TechnicalProfile>
The second step that checks the email and then writes the user:
<TechnicalProfile Id="verifyEmailsignup">
<DisplayName>Verify email signup</DisplayName>
<Protocol Name="Proprietary"
Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="GetLocalizedStringsForEmail" />
<InputClaimsTransformation ReferenceId="CreateReadonlyEmailClaim" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="readOnlyEmail" />
</InputClaims>
<DisplayClaims>
<DisplayClaim DisplayControlReferenceId="emailVerificationControlSignup" />
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="readOnlyEmail" Required="true" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="newUser" />
<!-- Optional claims, to be collected from the user -->
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surName" />
<OutputClaim ClaimTypeReferenceId="extension_companyName" />
<OutputClaim ClaimTypeReferenceId="country" />
<OutputClaim ClaimTypeReferenceId="city" />
<OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" Required="true" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="UserInputDisplayNameGenerator" />
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
UPDATE:
After escalating this issue for a while, it turns out that the password value can only be used on the step that it was collected on for security purposes. As such, creating the user on any subsequent step always creates it without a password and that means that the user is disabled.
In my project, I am now creating the user already on the password form step but disable it myself and then reenable it again after checking the email later. I hope this helps.