Custom policy in Azure AD B2C does not allow to save empty string for attribute - azure-ad-b2c

We have custom edit profile policy, which is based on the example provided by Microsoft, the policy has Company and Phone claims, which are not required.
When Company or Phone claim is left blank it still contains an old value after the profile is saved.
We have found, that there is a setting ConvertEmptyClaimsToNull, which is true by default, also we have tried https://learn.microsoft.com/en-us/azure/active-directory-b2c/string-transformations#nullclaim, but this did not help.
Edit profile policy:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId=""
PolicyId=""
PublicPolicyUri="">
<BasePolicy>
<TenantId></TenantId>
<PolicyId></PolicyId>
</BasePolicy>
<RelyingParty>
<DefaultUserJourney ReferenceId="ProfileEdit" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
<OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="email" />
<OutputClaim ClaimTypeReferenceId="country" />
<OutputClaim ClaimTypeReferenceId="city" />
<OutputClaim ClaimTypeReferenceId="extension_Company" />
<OutputClaim ClaimTypeReferenceId="extension_Phone" />
<OutputClaim ClaimTypeReferenceId="extension_MarketingConsent" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>
TrustFrameworkBase:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId=""
PolicyId="B2C_1A_TrustFrameworkBase"
PublicPolicyUri="">
<ClaimsProviders>
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<DisplayName>Local Account SignIn</DisplayName>
<Protocol Name="OpenIdConnect" />
<Metadata>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We can't seem to find your account</Item>
<Item Key="UserMessageIfInvalidPassword">Your password is incorrect</Item>
<Item Key="UserMessageIfOldPasswordUsed">Looks like you used an old password</Item>
<Item Key="ProviderName">https://sts.windows.net/</Item>
<Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item>
<Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item>
<Item Key="response_types">id_token</Item>
<Item Key="response_mode">query</Item>
<Item Key="scope">email openid</Item>
<!-- Policy Engine Clients -->
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="HttpBinding">POST</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="username" Required="true" />
<InputClaim ClaimTypeReferenceId="password" Required="true" />
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" />
<InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
<OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid" />
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
<OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="country" PartnerClaimType="country" />
<OutputClaim ClaimTypeReferenceId="city" PartnerClaimType="city" />
<OutputClaim ClaimTypeReferenceId="extension_Company" PartnerClaimType="extension_Company" />
<OutputClaim ClaimTypeReferenceId="extension_Phone" PartnerClaimType="extension_Phone" />
<OutputClaim ClaimTypeReferenceId="extension_MarketingConsent" PartnerClaimType="extension_MarketingConsent" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-Common">
<DisplayName>Azure Active Directory</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ApplicationObjectId">831fb406-f72d-4a18-b45c-325c87791ed0</Item>
<Item Key="ClientId">bfde7a7f-c0a1-417e-b609-4e1d598881ef</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<!-- We need this here to suppress the SelfAsserted provider from invoking SSO on validation profiles. -->
<IncludeInSso>false</IncludeInSso>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<!-- Technical profiles for local accounts -->
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password" />
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration" />
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
<PersistedClaim ClaimTypeReferenceId="country" />
<PersistedClaim ClaimTypeReferenceId="city" />
<PersistedClaim ClaimTypeReferenceId="extension_Company" />
<PersistedClaim ClaimTypeReferenceId="extension_Phone" />
<PersistedClaim ClaimTypeReferenceId="extension_MarketingConsent" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserReadUsingEmailAddress">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided user ID.</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
</InputClaims>
<OutputClaims>
<!-- Required claims -->
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<!-- Optional claims -->
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="accountEnabled" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="country" />
<OutputClaim ClaimTypeReferenceId="city" />
<OutputClaim ClaimTypeReferenceId="extension_Company" />
<OutputClaim ClaimTypeReferenceId="extension_Phone" />
<OutputClaim ClaimTypeReferenceId="extension_MarketingConsent" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="AssertAccountEnabledIsTrue" />
</OutputClaimsTransformations>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserWritePasswordUsingObjectId">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
<!-- Technical profiles for updating user record using objectId -->
<TechnicalProfile Id="AAD-UserWriteProfileUsingObjectId">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="objectId" />
<!-- Optional claims -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
<PersistedClaim ClaimTypeReferenceId="country" />
<PersistedClaim ClaimTypeReferenceId="city" />
<PersistedClaim ClaimTypeReferenceId="extension_Company" />
<PersistedClaim ClaimTypeReferenceId="extension_Phone" />
<PersistedClaim ClaimTypeReferenceId="extension_MarketingConsent" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
<!-- The following technical profile is used to read data after user authenticates. -->
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<OutputClaims>
<!-- Optional claims -->
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="country" />
<OutputClaim ClaimTypeReferenceId="city" />
<OutputClaim ClaimTypeReferenceId="extension_Company" />
<OutputClaim ClaimTypeReferenceId="extension_Phone" />
<OutputClaim ClaimTypeReferenceId="extension_MarketingConsent" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Self Asserted</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SelfAsserted-ProfileUpdate">
<DisplayName>User ID 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.profileupdate</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="userPrincipalName" />
<!-- Optional claims. These claims are collected from the user and can be modified. Any claim added here should be updated in the
ValidationTechnicalProfile referenced below so it can be written to directory after being updateed by the user, i.e. AAD-UserWriteProfileUsingObjectId. -->
<InputClaim ClaimTypeReferenceId="givenName" />
<InputClaim ClaimTypeReferenceId="surname" />
<InputClaim ClaimTypeReferenceId="country" />
<InputClaim ClaimTypeReferenceId="city" />
<InputClaim ClaimTypeReferenceId="extension_Company" />
<InputClaim ClaimTypeReferenceId="extension_Phone" />
<InputClaim ClaimTypeReferenceId="extension_MarketingConsent" />
</InputClaims>
<OutputClaims>
<!-- Required claims -->
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<!-- Optional claims. These claims are collected from the user and can be modified. Any claim added here should be updated in the
ValidationTechnicalProfile referenced below so it can be written to directory after being updateed by the user, i.e. AAD-UserWriteProfileUsingObjectId. -->
<OutputClaim ClaimTypeReferenceId="givenName" Required="true" />
<OutputClaim ClaimTypeReferenceId="surName" Required="true" />
<OutputClaim ClaimTypeReferenceId="country" Required="true"/>
<OutputClaim ClaimTypeReferenceId="city" Required="true" />
<OutputClaim ClaimTypeReferenceId="extension_Company" />
<OutputClaim ClaimTypeReferenceId="extension_Phone" />
<OutputClaim ClaimTypeReferenceId="extension_MarketingConsent" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteProfileUsingObjectId" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Local Account</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<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="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="language.button_continue">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.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="displayName" />-->
<OutputClaim ClaimTypeReferenceId="givenName" Required="true" />
<OutputClaim ClaimTypeReferenceId="surName" Required="true" />
<OutputClaim ClaimTypeReferenceId="country" Required="true"/>
<OutputClaim ClaimTypeReferenceId="city" Required="true" />
<OutputClaim ClaimTypeReferenceId="extension_Company" />
<OutputClaim ClaimTypeReferenceId="extension_Phone" />
<OutputClaim ClaimTypeReferenceId="extension_MarketingConsent" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
<!-- This technical profile uses a validation technical profile to authenticate the user. -->
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonEmailExchange</Item>
<Item Key="setting.operatingMode">Email</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
<!-- This technical profile forces the user to verify the email address that they provide on the UI. Only after email is verified, the user account is
read from the directory. -->
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
<DisplayName>Reset password using email address</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
<Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<IncludeInSso>false</IncludeInSso>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
<TechnicalProfile Id="LocalAccountWritePasswordUsingObjectId">
<DisplayName>Change password (username)</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.localaccountpasswordreset</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWritePasswordUsingObjectId" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Session Management</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SM-Noop">
<DisplayName>Noop Session Management Provider</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.SSO.NoopSSOSessionProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</TechnicalProfile>
<TechnicalProfile Id="SM-AAD">
<DisplayName>Session Mananagement Provider</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.SSO.DefaultSSOSessionProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="email" />
<PersistedClaim ClaimTypeReferenceId="authenticationSource" />
<PersistedClaim ClaimTypeReferenceId="identityProvider" />
<PersistedClaim ClaimTypeReferenceId="newUser" />
<PersistedClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectIdFromSession" DefaultValue="true" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Trustframework Policy Engine TechnicalProfiles</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="TpEngine_c3bd4fe2-1775-4013-b91d-35f16d377d13">
<DisplayName>Trustframework Policy Engine Default Technical Profile</DisplayName>
<Protocol Name="None" />
<Metadata>
<Item Key="url">{service:te}</Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Token Issuer</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="JwtIssuer">
<DisplayName>JWT Issuer</DisplayName>
<Protocol Name="None" />
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="client_id">{service:te}</Item>
<Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item>
<Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
<Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer" />
</CryptographicKeys>
<InputClaims />
<OutputClaims />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
</TrustFrameworkPolicy>

Just use AllowGenerationOfClaimsWithNullValues metadata item in the policy you want to save empty values.
<Metadata>
<Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
</Metadata>

Related

How to update an Azure AD B2C Username sample for sending custom emails with SendGrid?

I'm using this policy for Username-based SUSI extended off of this starter pack for local account SUSI. But I had also changed that starter pack for custom verification emails with SendGrid according to the how-to found here. The requirements for login went from "just use B2C" to "login with a username and any number of users may share a verification email."
I know that TrustFrameworkExtensions_Username is extending TrustFrameworkExtensions from the local account starter pack. I can apply the same overrides from the "Local Account" ClaimsProvider over the LocalAccountSignUpWithLogonEmail and LocalAccountDiscoveryUsingEmailAddress TechnicalProfiles to the "Local Account SignIn" ClaimsProvider's LocalAccountSignUpWithLogonName and LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress TechnicalProfiles directly.
The policy inheritance looks like this:
LocalAccounts starter pack TrustFrameworkBase
|
v
LocalAccounts starter pack TrustFrameworkLocalization
|
v
LocalAccounts starter pack TrustFrameworkExtensions <- modified for custom emails via SendGrid
|
v
username-signup-or-signin sample TrustFrameworkExtenions_Username
| |
v v
username-signup-or-signin sample SignupOrSignin_Username and PasswordReset_Username
The display controls in local extensions from the how-to:
<DisplayControls>
<DisplayControl Id="emailVerificationControl" UserInterfaceControlType="VerificationControl">
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="email" Required="true" />
<DisplayClaim ClaimTypeReferenceId="verificationCode" ControlClaimType="VerificationCode" Required="true" />
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" />
</OutputClaims>
<Actions>
<Action Id="SendCode">
<ValidationClaimsExchange>
<ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="GenerateOtp" />
<ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="SendOtp" />
</ValidationClaimsExchange>
</Action>
<Action Id="VerifyCode">
<ValidationClaimsExchange>
<ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="VerifyOtp" />
</ValidationClaimsExchange>
</Action>
</Actions>
</DisplayControl>
</DisplayControls>
Tech profiles referenced from the display controls:
<ClaimsProvider>
<DisplayName>One time password technical profiles</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="GenerateOtp">
<DisplayName>Generate one time password</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.OneTimePasswordProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="Operation">GenerateCode</Item>
<Item Key="CodeExpirationInSeconds">1200</Item>
<Item Key="CodeLength">6</Item>
<Item Key="CharacterSet">0-9</Item>
<Item Key="ReuseSameCode">true</Item>
<Item Key="NumRetryAttempts">5</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="identifier" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="otp" PartnerClaimType="otpGenerated" />
</OutputClaims>
</TechnicalProfile>
<TechnicalProfile Id="VerifyOtp">
<DisplayName>Verify one time password</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.OneTimePasswordProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="Operation">VerifyCode</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="identifier" />
<InputClaim ClaimTypeReferenceId="verificationCode" PartnerClaimType="otpToVerify" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>RestfulProvider</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SendOtp">
<DisplayName>Use SendGrid's email API to send the code the the user</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://api.sendgrid.com/v3/mail/send</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="ClaimUsedForRequestPayload">emailRequestBody</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BearerAuthenticationToken" StorageReferenceId="B2C_1A_SendGridSecret" />
</CryptographicKeys>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="GenerateEmailRequestBody" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="emailRequestBody" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
The SUSI tech profile overrides in the local extensions:
<ClaimsProvider>
<DisplayName>Local Account</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<DisplayClaims>
<DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
<DisplayClaim ClaimTypeReferenceId="givenName" Required="true" />
<DisplayClaim ClaimTypeReferenceId="surName" Required="true" />
<DisplayClaim ClaimTypeReferenceId="newPassword" Required="true" />
<DisplayClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
</DisplayClaims>
</TechnicalProfile>
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
<DisplayClaims>
<DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
</DisplayClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
I can get the sign-up part of the journey working in this manner - I could take the overrides in the extension changes found in the how-to here and add the DisplayClaims to the LocalAccountSignUpWithLogonName TechnicalProfile in
TrustFrameworkExtensions_Username.xml:
<TechnicalProfile Id="LocalAccountSignUpWithLogonName">
<DisplayName>User ID signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="LocalAccountType">Username</Item>
<Item Key="LocalAccountProfile">true</Item>
<Item Key="language.button_continue">Create</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="signInName" Required="true" />
<DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
<DisplayClaim ClaimTypeReferenceId="newPassword" Required="true" />
<DisplayClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" Required="true" />
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="email" Required="true" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="newUser" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonName" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
From the OutputClaim with ClaimTypeReferenceId=email PartnerClaimType="Verified.Email" was removed. Not necessary for getting the display control actually used but for later use of the email claim in the claim bag in a subsequent orchestration step (was not set otherwise).
But when updating the TechnicalProfile for LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress in a similar way:
<TechnicalProfile Id="LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress">
<DisplayName>Reset password using username</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountpasswordchange1.1</Item>
<Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
<Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">An account could not be found for the provided user ID.</Item>
<Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
<Item Key="LocalAccountType">Username</Item>
<Item Key="LocalAccountProfile">true</Item>
<!-- Reduce the default self-asserted retry limit of 7 for the reset journey -->
<Item Key="setting.retryLimit">3</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<!-- using this requires removal of OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true", below
according to https://stackoverflow.com/a/73709880/2347078 -->
<!-- line is required for non-customized email journey presently -->
<DisplayClaims>
<DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<!-- <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" /> -->
<OutputClaim ClaimTypeReferenceId="email" Required="true" />
<OutputClaim ClaimTypeReferenceId="emails" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="sub" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" />
</OutputClaimsTransformations>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingUserNameAndValidateStrongAuthenticationEmailAddress" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
In this case, see the comments as to why the OutputClaim with ClaimTypeReferenceId="email" was modified, which is referencing Jas Suri - MSFT below. With the OutputClaim looking like <OutputClaim ClaimTypeReferenceId="email" Required="true" /> the display claim is ignored entirely (the built-in verification control is presented).
With the OutputClaim entirely removed, instead the password reset policy winds up not having any fields:
All starter packs/samples are from current repos, and are using v2 pages supporting display claims.
Remove
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />

Azure B2C: Email not displayed during Email MFA

I am using B2C custom policies which allows signup/signin with the username instead of the email. I have Email MFA enforced during the sign Up.
When signing in and selecting Email MFA, I don't see the email populated.
I have implemented the policies provided in this article https://github.com/azure-ad-b2c/samples/tree/master/policies/mfa-email-or-phone
<!--MFA related Attributes-->
<ClaimType Id="extension_mfaByPhoneOrEmail">
<DisplayName>Please select your preferred MFA method</DisplayName>
<DataType>string</DataType>
<UserInputType>RadioSingleSelect</UserInputType>
<Restriction>
<Enumeration Text="Phone" Value="phone" SelectByDefault="true" />
<Enumeration Text="Email " Value="email" SelectByDefault="false" />
</Restriction>
</ClaimType>
<ClaimType Id="readOnlyEmail">
<DisplayName>Email Address</DisplayName>
<DataType>string</DataType>
<UserHelpText/>
<UserInputType>Readonly</UserInputType>
</ClaimType>
<ClaimType Id="newPhoneNumberEntered">
<DisplayName>New Phone Number Entered</DisplayName>
<DataType>boolean</DataType>
</ClaimType>
<ClaimType Id="userIdForMFA">
<DisplayName>UserId for MFA</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="strongAuthenticationPhoneNumber">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<Mask Type="Simple">XXX-XXX-</Mask>
<UserHelpText>Your telephone number</UserHelpText>
</ClaimType>
<ClaimType Id="Verified.strongAuthenticationPhoneNumber">
<DisplayName>Verified Phone Number</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OpenIdConnect" PartnerClaimType="phone_number" />
</DefaultPartnerClaimTypes>
<Mask Type="Simple">XXX-XXX-</Mask>
<UserHelpText>Your office phone number that has been verified</UserHelpText>
</ClaimType>
</ClaimsSchema>
<ClaimsTransformations>
<!--MFA related Transformation Start-->
<ClaimsTransformation Id="CopySignInNameToReadOnly" TransformationMethod="FormatStringClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" TransformationClaimType="inputClaim" /> <!--signInName-->
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0}" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="readOnlyEmail" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CopyEmailToReadOnly" TransformationMethod="FormatStringClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0}" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="readOnlyEmail" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CreateUserIdForMFA" TransformationMethod="FormatStringClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0}#{RelyingPartyTenantId}" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="userIdForMFA" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<!--MFA related transformation end-->
<ClaimsTransformation Id="CreateSubjectClaimFromObjectID" TransformationMethod="CreateStringClaim">
<InputParameters>
<InputParameter Id="value" DataType="string" Value="Not supported currently. Use oid claim." />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="sub" TransformationClaimType="createdClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CreateEmailsFromOtherMailsAndSignInNamesInfo" TransformationMethod="AddItemToStringCollection">
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInNamesInfo.emailAddress" TransformationClaimType="item" />
<InputClaim ClaimTypeReferenceId="otherMails" TransformationClaimType="collection" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="emails" TransformationClaimType="collection" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="AddStrongAuthenticationEmailToEmails" TransformationMethod="AddItemToStringCollection">
<InputClaims>
<InputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" TransformationClaimType="item" />
<InputClaim ClaimTypeReferenceId="emails" TransformationClaimType="collection" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="emails" TransformationClaimType="collection" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="AssertEmailAndstrongAuthenticationEmailAddressAreEqual" TransformationMethod="AssertStringClaimsAreEqual">
<InputClaims>
<!--<InputClaim ClaimTypeReferenceId="mail" TransformationClaimType="inputClaim1" /> -->
<InputClaim ClaimTypeReferenceId="email" TransformationClaimType="inputClaim1" />
<InputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" TransformationClaimType="inputClaim2" />
</InputClaims>
<InputParameters>
<InputParameter Id="stringComparison" DataType="string" Value="ordinalIgnoreCase" />
</InputParameters>
</ClaimsTransformation>
<ClaimsTransformation Id="AssertAccountEnabledIsTrue" TransformationMethod="AssertBooleanClaimIsEqualToValue">
<InputClaims>
<InputClaim ClaimTypeReferenceId="accountEnabled" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="valueToCompareTo" DataType="boolean" Value="true" />
</InputParameters>
</ClaimsTransformation>
</ClaimsTransformations>
<!--defination for MFA phone factor-->
<ContentDefinition Id="api.phonefactor">
<LoadUri>~/tenant/templates/AzureBlue/multifactor-1.0.0.cshtml</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:multifactor:1.2.5</DataUri>
<Metadata>
<Item Key="DisplayName">Multi-factor authentication page</Item>
</Metadata>
</ContentDefinition>
</ContentDefinitions>
</BuildingBlocks>
<ClaimsProviders>
<!--mFA related-->
<ClaimsProvider>
<DisplayName>Local Account</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CopyEmailToReadOnly" />
</OutputClaimsTransformations>
</TechnicalProfile>
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CopySignInNameToReadOnly" />
</OutputClaimsTransformations>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<!--end of mFa related-->
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-UserWriteUsingLogonName">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<!--Include the Claims Transformation to populate displayName using the first name and Last name combination-->
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CreateDisplayNameFromFirstNameAndLastName" />
<InputClaimsTransformation ReferenceId="CreateOtherMailsFromEmail" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="signInNames.userName" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="signInName" PartnerClaimType="signInNames.userName" />
<!--<PersistedClaim ClaimTypeReferenceId="mail" PartnerClaimType="strongAuthenticationEmailAddress" /> -->
<PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="strongAuthenticationEmailAddress" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password" />
<PersistedClaim ClaimTypeReferenceId="displayName" PartnerClaimType= "displayName" /> <!--DefaultValue="SomeDefaultDisplayNameValue" DefaultValue="unknownUser"-->
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
<PersistedClaim ClaimTypeReferenceId="otherMails" /> <!--added on 02162022-->
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="displayName" /> <!--displayName attribute added- partner claim type Name added-->
<OutputClaim ClaimTypeReferenceId="otherMails" /> <!--added on02162022-->
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="strongAuthenticationEmailAddress" /> <!--added on 02172022-->
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
<TechnicalProfile Id="LocalAccountSignUpWithLogonName">
<DisplayName>User ID signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="LocalAccountType">Username</Item>
<Item Key="LocalAccountProfile">true</Item>
<Item Key="language.button_continue">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" Required="true" />
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<!-- <OutputClaim ClaimTypeReferenceId="mail" PartnerClaimType="Verified.Email" Required="true" /> -->
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="newUser" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="givenName" Required="true" />
<OutputClaim ClaimTypeReferenceId="surname" Required="true" />
<OutputClaim ClaimTypeReferenceId="displayName" Required="true" /> <!--Display Name added-->
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonName" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
<!--AAD User read using Username-->
<TechnicalProfile Id="AAD-UserReadUsingUsername-NoError">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided user ID.</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="signInNames.userName" Required="true" />
</InputClaims>
<OutputClaims>
<!-- Required claims -->
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
<!--
<OutputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
<OutputClaim ClaimTypeReferenceId="secondaryStrongAuthenticationPhoneNumber" PartnerClaimType="strongAuthenticationAlternativePhoneNumber" />
-->
<!-- Optional claims -->
<OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
<!--AAD User read using Username-->
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Username">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonUsernameExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
<TechnicalProfile Id="LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress">
<DisplayName>Reset password using username</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountpasswordchange1.1</Item>
<Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
<Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">An account could not be found for the provided user ID.</Item>
<Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
<Item Key="LocalAccountType">Username</Item>
<Item Key="LocalAccountProfile">true</Item>
<!-- Reduce the default self-asserted retry limit of 7 for the reset journey -->
<Item Key="setting.retryLimit">3</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<!-- <OutputClaim ClaimTypeReferenceId="mail" PartnerClaimType="Verified.Email" Required="true" /> -->
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="emails" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="sub" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" />
</OutputClaimsTransformations>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingUserNameAndValidateStrongAuthenticationEmailAddress" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserReadUsingUserNameAndValidateStrongAuthenticationEmailAddress">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="signInNames.userName" Required="true" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="accountEnabled" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
<OutputClaim ClaimTypeReferenceId="displayName" /> <!--displayName added to Claims-->
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="AssertEmailAndstrongAuthenticationEmailAddressAreEqual" />
<OutputClaimsTransformation ReferenceId="AssertAccountEnabledIsTrue" />
<OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" />
</OutputClaimsTransformations>
<IncludeTechnicalProfile ReferenceId="AAD-ReadCommon" />
</TechnicalProfile>
<TechnicalProfile Id="AAD-ReadCommon">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
<OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" PartnerClaimType="signInNames.emailAddress" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateEmailsFromOtherMailsAndSignInNamesInfo" />
<OutputClaimsTransformation ReferenceId="AddStrongAuthenticationEmailToEmails" />
</OutputClaimsTransformations>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
<TechnicalProfile Id="SelfAsserted-Input">
<DisplayName>Self Asserted</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>
<Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<!-- Note: Claims such as emails are not listed here because without a ValidationTechnicalProfile when SelfAsserted-Input is shown to the user,
the user will be prompted for such claims. As a result, that claim is kept in the technical profiles that have ValidationTechnicalProfile -->
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<!-- tech profile for MFA related work Start-->
<ClaimsProvider>
<DisplayName>Self Asserted</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SelfAsserted-Select-MFA-Method">
<DisplayName>Allow user to choose their MFA Method</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>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="extension_mfaByPhoneOrEmail" Required="true"/>
</OutputClaims>
</TechnicalProfile>
<TechnicalProfile Id="EmailVerifyOnSignIn">
<DisplayName>EmailVerifyOnSignIn</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>
<InputClaims>
<InputClaim ClaimTypeReferenceId="readOnlyEmail" />
</InputClaims>
<OutputClaims>
<!-- Required claims -->
<OutputClaim ClaimTypeReferenceId="isActiveMFASession" DefaultValue="true"/>
<OutputClaim ClaimTypeReferenceId="readOnlyEmail" PartnerClaimType="Verified.Email"/>
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteMFAMethod">
</ValidationTechnicalProfile>
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-UserWriteMFAMethod">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="userPrincipalName" />
<PersistedClaim ClaimTypeReferenceId="extension_mfaByPhoneOrEmail" />
<PersistedClaim ClaimTypeReferenceId="displayName" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
<!--MFA user Journey started-->
<UserJourney Id="SignUpOrSignInMFAOption">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninUsernameExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninUsernameExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Username" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Check if the user has selected to sign in using one of the social providers -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonUsernameExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonName" />
</ClaimsExchanges>
</OrchestrationStep>
<!--Sample: If uses is enrolled for MFA, ask the user to select the preferred method-->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>extension_mfaByPhoneOrEmail</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SelfAsserted-Select-MFA-Method" TechnicalProfileReferenceId="SelfAsserted-Select-MFA-Method" />
</ClaimsExchanges>
</OrchestrationStep>
<!--Sample: MFA with email-->
<OrchestrationStep Order="7" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false" >
<Value>extension_mfaByPhoneOrEmail</Value>
<Value>email</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="Email-Verify" TechnicalProfileReferenceId="EmailVerifyOnSignIn" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="8" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/>
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb"/>
</UserJourney>
<!-- MFA user Journey ended-->
The problem is that "strongAuthenticationEmailAddress" is null then.
The copy is done in "SelfAsserted-LocalAccountSignin-Email" in step 1.
"strongAuthenticationEmailAddress" is only available after the read in step 3.

Azure B2C - Terms of Service checkbox for Social Signup/Signin

I would like to display the Terms of Service checkbox after the user signs up through an IDP (Facebook, Google, etc.) How can I achieve this?
I am however encountering "The page cannot be displayed because an internal server error has occurred." after sign up.
Below are snippets of my code so far:
<TechnicalProfile Id="SelfAsserted-Social">
<DisplayName>User ID 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>
<InputClaims>
<InputClaim ClaimTypeReferenceId="displayName"/>
<InputClaim ClaimTypeReferenceId="surname" />
<InputClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" DefaultValue="AgreeToTermsOfUseConsentNo" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
<OutputClaim ClaimTypeReferenceId="newUser" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="displayName"/>
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" Required="true" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
<ValidationTechnicalProfile ReferenceId="REST-SignUp" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialSignup" /></TechnicalProfile>
<TechnicalProfile Id="AAD-UserWriteUsingAlternativeSecurityId">
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
<PersistedClaim ClaimTypeReferenceId="currentTime" PartnerClaimType="extension_termsOfUseConsentDateTime" />
<PersistedClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" />
<PersistedClaim ClaimTypeReferenceId="extension_termsOfUseConsentVersion" DefaultValue="V1" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="objectId" />
</OutputClaims>
</TechnicalProfile>
Created a new sample here which demonstrates the flow:
https://github.com/azure-ad-b2c/samples/tree/master/policies/sign-in-sign-up-versioned-tou-with-social

Azure Active Directory B2C Custom Policy - Incoming name claims from jwt invite policy

I am trying to pass surname, givenName, and displayName claims from a JWT token using the id_token_hint parameter as specified in this sample: https://github.com/azure-ad-b2c/samples/tree/master/policies/invite
I have followed similar steps to those specified in this post:Azure Active Directory B2C Custom Invite Policy - Passing Custom Claims Between Steps
My issue is that the name claims are not persisted to the user's profile (I can see they exist in the id_token_hint parameter) and are also not provided in the access token, even though email and testclaim1 are returned in the token.
My onboarding RP:
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="givenName" />
<InputClaim ClaimTypeReferenceId="surname" />
<InputClaim ClaimTypeReferenceId="displayName" />
<InputClaim ClaimTypeReferenceId="testclaim1" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="testclaim1" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="email" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="Local" />
<OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
IdTokenHint_ExtractClaims technical profile:
<DisplayName>My ID Token Hint ClaimsProvider</DisplayName>
<!--Required for inviting user with token-->
<TechnicalProfiles>
<TechnicalProfile Id="IdTokenHint_ExtractClaims">
<DisplayName> My ID Token Hint TechnicalProfile</DisplayName>
<Protocol Name="None" />
<Metadata>
<Item Key="METADATA">{Settings:WebAppInviteUrl}</Item>
<!-- <Item Key="IdTokenAudience">your_optional_audience_override</Item> -->
<!-- <Item Key="issuer">your_optional_token_issuer_override</Item> -->
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="testclaim1" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
LocalAccountSignUpWithReadOnlyEmail technical profile:
<TechnicalProfile Id="LocalAccountSignUpWithReadOnlyEmail">
<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="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="language.button_continue">Create</Item>
<!-- Sample: Remove sign-up email verification -->
<Item Key="EnforceEmailVerification">False</Item>
</Metadata>
<InputClaimsTransformations>
<!--Sample: Copy the email to ReadOnlyEamil claim type-->
<InputClaimsTransformation ReferenceId="CopyEmailAddress" />
</InputClaimsTransformations>
<InputClaims>
<!--Sample: Set input the ReadOnlyEmail claim type to prefilled the email address-->
<InputClaim ClaimTypeReferenceId="ReadOnlyEmail" />
<InputClaim ClaimTypeReferenceId="displayName" />
<InputClaim ClaimTypeReferenceId="givenName" />
<InputClaim ClaimTypeReferenceId="surname" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
<PersistedClaim ClaimTypeReferenceId="displayName" />
<PersistedClaim ClaimTypeReferenceId="testclaim1" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<!-- Sample: Display the ReadOnlyEmail claim type (instead of email claim type)-->
<OutputClaim ClaimTypeReferenceId="ReadOnlyEmail" PartnerClaimType="Verified.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" />
<!-- If the user has already verified their email address -->
<OutputClaim ClaimTypeReferenceId="extension_EmailIsVerified" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="displayName" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
<!-- Sample: Disable session management for sign-up page -->
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
AAD-UserWriteUsingLogonEmail technical profile:
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisableStrongPassword, DisablePasswordExpiration" />
<PersistedClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" PartnerClaimType="strongAuthenticationPhoneNumber" />
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="displayName" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
I didn't figure out the reason this was occurring, but I did discover a workaround. I updated the jwt token to change the names of givenName, surname, and displayName properties and then I added the PartnerClaimType attribute to the relying party InputClaim elements to map my jwt claims back to what my custom policy expects
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName" />
<InputClaim ClaimTypeReferenceId="surname" PartnerClaimType="lastName" />
<InputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="adDisplayName"/>
</InputClaims>

Output claims does not contain email after login in Azure AD B2c

I am using azure ad b2c custom policies for user signIn and signUp.
I am trying to get user's email as part of the output claims, unfortunately unable to get email in output claims.
I am using SignUpOrSignIn user journey in template policy
TrustFrameworkBase.xml
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<DisplayName>Local Account SignIn</DisplayName>
<Protocol Name="OpenIdConnect" />
<Metadata>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We can't seem to find your account</Item>
<Item Key="UserMessageIfInvalidPassword">Your password is incorrect</Item>
<Item Key="UserMessageIfOldPasswordUsed">Looks like you used an old password</Item>
<Item Key="ProviderName">https://sts.windows.net/</Item>
<Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item>
<Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item>
<Item Key="response_types">id_token</Item>
<Item Key="response_mode">query</Item>
<Item Key="scope">email openid</Item>
<!-- Policy Engine Clients -->
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="HttpBinding">POST</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="username" Required="true" />
<InputClaim ClaimTypeReferenceId="password" Required="true" />
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" />
<InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
<OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid" />
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
<OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
<Item Key="scope">openid email</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<OutputClaims>
<!-- Optional claims -->
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="city" />
<OutputClaim ClaimTypeReferenceId="postalCode" />
<OutputClaim ClaimTypeReferenceId="jobTitle" />
<OutputClaim ClaimTypeReferenceId="streetAddress" />
<OutputClaim ClaimTypeReferenceId="state" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email"/>
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonEmailExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignin</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="signInNames.userName" Required="true" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="email" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<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="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="language.button_continue">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="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="displayName" />
<OutputClaim ClaimTypeReferenceId="jobTitle" />
<OutputClaim ClaimTypeReferenceId="postalCode" />
<OutputClaim ClaimTypeReferenceId="city" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surName" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="newUser" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<!--gscott added -->
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
Template policy
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignIn" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="otherMails"/>
<OutputClaim ClaimTypeReferenceId="userPrincipalName"/>
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="email"/>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="city" />
<OutputClaim ClaimTypeReferenceId="postalCode" />
<OutputClaim ClaimTypeReferenceId="jobTitle" />
<OutputClaim ClaimTypeReferenceId="streetAddress" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
I have tried to find all the other answered questions, but was not able succeed.
Any direction and help is much appreciated.
Thanks in advance.

Resources