Azure B2C Rest API in User Journey body is empty - azure-ad-b2c

I have a REST API call that I can call just fine using a validation technical profile, but if I add it to a user journey as an orchestration step, the body of the call is null when it gets to the backend API, thus erring. I have following all the Microsoft Documentation and everything appears to be setup correctly. The calls are in different IEF policies, but they all have the exact same REST Technical Profile.
Here is the technical profile:
<TechnicalProfile Id="RESTTransactionalEmail">
<DisplayName>REST API to Update the backend </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://{Settings:APIURI}/apiendpoint</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="<key>" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="<secret>" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="extension_{Settings:ExtensionAppId}_memberid" PartnerClaimType="memberId"/>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="toRecipient"/>
<InputClaim ClaimTypeReferenceId="templateName" PartnerClaimType="templateName" />
<InputClaim ClaimTypeReferenceId="key" PartnerClaimType="modelKey1" />
<InputClaim ClaimTypeReferenceId="phoneChange" PartnerClaimType="modelValue1" />
</InputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
This is the orchestration step:
<OrchestrationStep Order="11" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="RESTSendEmail" TechnicalProfileReferenceId="RESTTransactionalEmail" />
</ClaimsExchanges>
</OrchestrationStep>
Has anyone else run into this or have any suggestions on what to try?

Related

Technical Profile fails to match user account with email (signInNames.emailAddress) claim

Can anyone explain to me (before Azure B2C Custom Policies make me pull what's left of my hair out), why this technical profile fails to ever return an "objectId" when a user account exists in Azure B2C. I am collecting the email claim in a previous screen and calling the technical profile from the orchestration step.
I can see the profile executing in my Application Insights logs and I have confirmed that the email address I use in the claim is in the directory. But every time, no matter which email address I use, I never get an objectId back which means I can never detect if the user exists or not!
Technical Profile
<TechnicalProfile Id="UE-AAD-CheckAccountExistsByEmail">
<Protocol Name="Proprietary"
Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided email address.</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
Orchestration Step
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<!-- Skip this if we already have an object id from single signon -->
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectIdFromSession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<!-- Call a technical profile to see if an account can be found with the email supplied in AD -->
<ClaimsExchange Id="AccountExistsClaim"
TechnicalProfileReferenceId="UE-AAD-CheckAccountExistsByEmail" />
</ClaimsExchanges>
</OrchestrationStep>
You have specified ClaimsTransformationProtocolProvider as the handler.
You need the AAD provider as the handler to make Graph API queries.
Though if AAD-Common already has the Protocol element, you don't need to specify it here again since it'll be included from there.
Like so:
<TechnicalProfile Id="UE-AAD-CheckAccountExistsByEmail">
<!-- You don't actually need this though if AAD-Common has it -->
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided email address.</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
ClaimsTransformationProtocolProvider is used for running claims transformations to produce new claims or modify existing claims.
It is not used for querying AAD.

B2C Validation of REST API

IN our forgot password flow, I want to do a REST API call to do a validation check on the account. We have a database that we need to do a check against.
During this process, the API will return a 200 or 400.
If its a 200, I want them to continue on with the orchestration of forgot password.
If it is a 400, instead of pulling them out of the flow and putting them back in the application, I would rather show them that there is a problem with their account and to contact our support or to register a new account.
However, no matter what the response, in my current code it is send them along in the orchestration step.
This is the orchestration step:
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="GetMemberClaimsExchange" TechnicalProfileReferenceId="MemberAccountHolderCollector" />
</ClaimsExchanges>
</OrchestrationStep>
then this is my claims provider.
<ClaimsProvider>
<DisplayName>REST API to Check Member Status</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="MemberAccountHolderCollector">
<DisplayName>Collect Member Info Technical Profile</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.register</Item>
</Metadata>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-CheckMemberAccountHolder" ContinueOnError="true"/>
</ValidationTechnicalProfiles>
</TechnicalProfile>
<TechnicalProfile Id="REST-CheckMemberAccountHolder">
<DisplayName>Rest API call to Check Member status</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">{API}</Item>
<Item Key="SendClaimsIn">QueryString</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailaddress"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailaddress" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
The api.selfasserted.register is simply a template i created. I don't need to use it. I could just throw the error on the screen as anything, but I was just trying anything to get it to work.
Any help is appreciated here.
Edit:
Thank you for the advice, so i think i understand where your going.
I added a claim type
<ClaimType Id="requireRegister">
<DisplayName>requireRegster</DisplayName>
<DataType>boolean</DataType>
<UserInputType>Paragraph</UserInputType>
</ClaimType>
The idea would be that I can do an output claim.
The problem is when i do this...
<TechnicalProfiles>
<TechnicalProfile Id="MemberAccountHolderCollector">
<DisplayName>Collect Member Info Technical Profile</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.register</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="requireRegister" DefaultValue="true"/>
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-CheckMemberAccountHolder" ContinueOnError="true"/>
</ValidationTechnicalProfiles>
</TechnicalProfile>
It shows the page every time, which i don't want to do either...
Edit 2:
Our forgot password is done off this policy
[enter link description here][1]
[1]: https://learn.microsoft.com/en-us/azure/active-directory-b2c/add-password-reset-policy?pivots=b2c-custom-policy
in our policy when you click the forgot password button it invokes the subjourney
<SubJourneys>
<SubJourney Id="PasswordReset" Type="Call">
<OrchestrationSteps>
<!-- Validate user's email address. -->
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="PasswordResetUsingEmailAddressExchange" TechnicalProfileReferenceId="LocalAccountDiscoveryUsingEmailAddress" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Show TOU-->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SelfAssertedConsentExchange" TechnicalProfileReferenceId="SelfAsserted-PasswordResetConsent" />
</ClaimsExchanges>
</OrchestrationStep>
There is a custom page to show our TOU consent, before they get there, I need the account to run through our validation before.
Edit 3:
Doing the code below skips the Email validation step in the forgot password policy.
<ClaimsProvider>
<DisplayName>REST API to Check Member</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-CheckMemberAccount" ContinueOnError="false"/>
</ValidationTechnicalProfiles>
</TechnicalProfile>
<!--Not using anymore -->
<TechnicalProfile Id="MemberAccountHolderCollector">
<DisplayName>Collect Member Info Technical Profile</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.register</Item>
</Metadata>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-CheckMemberAccount" ContinueOnError="false"/>
</ValidationTechnicalProfiles>
</TechnicalProfile>
<TechnicalProfile Id="REST-CheckMemberAccount">
<DisplayName>Rest API call to Check Member status</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">{API}</Item>
<Item Key="SendClaimsIn">QueryString</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailaddress"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailaddress" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
This configuration, where there are no output claims as part of a selfAsserted technical profile, will cause B2C to skip this entire step.
You should be adding this as a validation technical profile on the previous step, where the user enters and validates their email. As follows:
<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" />
<OutputClaim ClaimTypeReferenceId="requireRegister" DefaultValue="true"/>
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
<ValidationTechnicalProfile ReferenceId="MemberAccountHolderCollector" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
Remove MemberAccountHolderCollector technical profile entirely. And any reference to that from your User Journey.
Now after the user validates their email, and submits the page, the REST API will be called. If it returns an error, it is displayed on the same screen where the user validated their email.
You must return a HTTP 409 conflict with proper error JSON payload for it to be displayed on the screen.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/restful-technical-profile#returning-validation-error-message

Azure B2C call azure function with JWT token or code kept as policy key

is it possible to call azure function without hardcoding function code in service url?
For example using policy key and sending it as query string/header. I don't want it to be exposed.
Alternative is to use AAD auth on app service level, but that would require generating JWT token before step "SendClaims" and it could possibly led to authenticated users having access to this function.
Thanks for any help.
Edit:
Ok, I did it as suggested and I got to a point where I have everything set up.
I can request a working token using postman and authorize properly to azure function.
I have debugged said token in user journey by outputting it as user claim (I confirmed that acquire step is working), but I get an error on calling function
AADB2C90027: Basic credentials specified for 'Azure-Functions-Notify-New-User-Registered' are invalid. Check that the credentials are correct and that access has been granted by the resource.
So far my xml file looks like that:
<ClaimsProvider>
<DisplayName>Aquire JWT token to call azure function</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="Azure-Functions-Notify-New-User-Registered-AccessToken">
<DisplayName>Acquire JWT token to call azure function</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://login.microsoftonline.com/{my-tenant}/oauth2/v2.0/token</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Form</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_NotifyNewUserRegisteredClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_NotifyNewUserRegisteredSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" AlwaysUseDefaultValue="true" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="https://{my-tenant}/{my-resoruce-id}/.default" AlwaysUseDefaultValue="true" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure-Functions-Notify-New-User-Registered</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="Azure-Functions-Notify-New-User-Registered">
<DisplayName>Call Azure Function when new user registers</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">{my-azure-function-with-function-code}</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="UseClaimAsBearerToken">bearerToken</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="bearerToken"/>
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
And my user journey:
<OrchestrationStep Order="7" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="Azure-Functions-Notify-New-User-Registered-AccessToken" TechnicalProfileReferenceId="Azure-Functions-Notify-New-User-Registered-AccessToken" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="8" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="Azure-Functions-Notify-New-User-Registered" TechnicalProfileReferenceId="Azure-Functions-Notify-New-User-Registered" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="9" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
Protect it with AAD. Get the JWT to the function app using this:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/secure-rest-api#oauth2-bearer-authentication
No you don’t need to worry about the user getting this JWT, that’s impossible unless you decide to output this JWT as a claim in the relying party section.

Custom Email verification in a single orchestration step in AD B2C Custom policies

I have a multi-step custom policy that first collects email from user and sends a verification code to the user when user clicks continue. The journey works fine. But the thing is validation of code is happening in next step. I need to bring that code validation in to the first orchestration step. I'm following the below doc to implement this journey:
"https://github.com/yoelhor/aadb2c-verification-code"
My technical profile is like the following:
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail-FirstStep">
<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">Send verification email</Item>
<Item Key="EnforceEmailVerification">False</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="verificationCode" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CopyEmailAsReadOnly" />
</OutputClaimsTransformations>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-API-SendVerificationEmail" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
and the validation tech profile as follows:
<TechnicalProfile Id="REST-API-SendVerificationEmail">
<DisplayName>Sign-Up send link</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://myweb.azurewebsites.net/api/Identity/SendVerificationCode</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="verificationCode" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
It cant be achieved currently, to call the REST API, the form must be submitted and that will cause the orchestration step to complete and move to the next one.
In a few weeks we will release how to achieve this, and without the use of an external REST API to generate and verify the OTP Codes. Stay tuned.

Azure AD B2C Custom Policy Update User Attribute With Static Value

I'm currently testing out a theory with Azure AD B2C that requires an update of a value on a user profile with a static value that is not input by a user. I have attempted to try and follow the path of a profile edit example but can't seem to make it work. At this point it does not matter what value I update I just want to be able to update a value, I have chosen the "state" attribute for this experiment.
I have the following orchestration step in a user journey:
<OrchestrationStep Order="5" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="UpdateStateValue" TechnicalProfileReferenceId="LocalAccountUpdateStateValue" /
</ClaimsExchanges>
</OrchestrationStep>
The technical profiles are as follows:
<TechnicalProfile Id="LocalAccountUpdateStateValue">
<DisplayName>Update Password Set Value</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="objectId" />
</InputClaims>
<OutputClaims>
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserUpdateStateValue" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserUpdateStateValue">
<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="state" DefaultValue="CA"/>
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
What I am basically attempting to do is each time through the user journey update the "state" value to "CA" but it doesn't seem to be working. I first tried to just reference the "AAD-UserUpdateStateValue" technical profile directly without success and then moved towards something more similar to the profile edit example.
We are admittedly new to Azure B2C so any help or reference to articles that could help is appreciated.

Resources