'Unable to pass query param to azure-ad-b2c custom policy and store values

I have a scenario where i have to pass a query parameter in the URL to my custom sign-up policy and so far all my attempts did not work. there seem to be something that i am missing following the guidelines i found in github. I am trying to pass LoyaltyNumber and i have this attribute defined in my policy as extension_LoyaltyNumber. Below is the snippet

my custom signup policy

<RelyingParty>
<DefaultUserJourney ReferenceId="SignUp" />
<UserJourneyBehaviors>
   <ContentDefinitionParameters>
    <Parameter Name="LoyaltyNumber">{OAUTH-KV:LoyaltyNumber}</Parameter>
  </ContentDefinitionParameters>
</UserJourneyBehaviors>
<TechnicalProfile Id="PolicyProfile">
  <DisplayName>PolicyProfile</DisplayName>
  <Protocol Name="OpenIdConnect" />
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="email" />
    <InputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" /> 
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="displayName" />
    <OutputClaim ClaimTypeReferenceId="givenName" />
    <OutputClaim ClaimTypeReferenceId="surname" />
    <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
    <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
    <OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
    <OutputClaim ClaimTypeReferenceId="extension_ValidPassword" />
    <OutputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" AlwaysUseDefaultValue="true"/>
  </OutputClaims>
  <SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>

in my TrustFrameworkExtension.xml, i have defined it in the Local Account as follows

<ClaimsProvider>
      <DisplayName>Local Account</DisplayName>
      <TechnicalProfiles>
        <!--Local account sign-up page-->
        <TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
        <Metadata>
            <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
        </Metadata>
       <InputClaims>
           <InputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" AlwaysUseDefaultValue="true" DefaultValue="{OAUTH-K:LoyaltyNumber}" />
         </InputClaims>                                                                      
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
            <OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
            <OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
            <OutputClaim ClaimTypeReferenceId="displayName" />
            <OutputClaim ClaimTypeReferenceId="givenName" />
            <OutputClaim ClaimTypeReferenceId="surName" />
        </OutputClaims>
      </TechnicalProfile>

       <TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
           <Metadata>
            <Item Key="setting.showSignupLink">false</Item>
          </Metadata>
        </TechnicalProfile>
       
      </TechnicalProfiles>
    </ClaimsProvider>

i also have it in the building bolocks section as...

<BuildingBlocks>
    <ClaimsSchema>
      <ClaimType Id="extension_LoyaltyNumber">
        <DisplayName>Loyality-Number</DisplayName>
        <DataType>string</DataType>
        <UserHelpText>Your loyality from your membership card</UserHelpText>
      </ClaimType>
  </ClaimsSchema>
  </BuildingBlocks>

i have it also to write to Azure Active Directory claims provider section as follows

<ClaimsProvider>
      <DisplayName>Azure Active Directory</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="AAD-Common">
          <Metadata>
            <!--Insert b2c-extensions-app application ID here, for example: 11111111-1111-1111-1111-111111111111-->  
            <Item Key="ClientId">11111111-1111-1111-1111-111111111111</Item>
            <!--Insert b2c-extensions-app application ObjectId here, for example: 22222222-2222-2222-2222-222222222222-->
            <Item Key="ApplicationObjectId">22222222-2222-2222-2222-222222222222</Item>
          </Metadata>
        </TechnicalProfile>

        <TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
          <PersistedClaims>
            <PersistedClaim ClaimTypeReferenceId="extension_LoyaltyNumber" />
          </PersistedClaims>
        </TechnicalProfile>

        <TechnicalProfile Id="AAD-UserReadUsingObjectId">
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" />
          </OutputClaims>
        </TechnicalProfile>

      </TechnicalProfiles> 
    </ClaimsProvider>

And the redirect happens from my web application using the following method

public void SignUpNewUser()
        {
            if (!Request.IsAuthenticated)
            {
                var authenticationProperties = new AuthenticationProperties();
                authenticationProperties.Dictionary.Add("LoyaltyNumber", "556677");
                authenticationProperties.RedirectUri = "/";
                HttpContext.GetOwinContext().Authentication.Challenge(authenticationProperties, Startup.SignUpPolicyId);

            }
        }

The result i am getting after the user sign-up for the custom attribute extension_LoyaltyNumber is {OAUTH-K:LoyaltyNumber}

Somehow the value 556677 i pass as a query param is not getting to this custom attribute and get stored in Azure user attribute

Can you help?

Thanks



Solution 1:[1]

Add

<OutputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" />

to LocalAccountSignUpWithLogonEmail. Output claims allow the claim to be used in subsequent orchestration steps.

In the <RelyingParty> section, change your output claim to the following, its already resolved so no need to resolve it again here:

<OutputClaim ClaimTypeReferenceId="extension_LoyaltyNumber" />

Solution 2:[2]

What I do when I want to have query string parameters handled is this:

Create a TechnicalProfile:

  <TechnicalProfile Id="GetMyParameter">
    <DisplayName>GetMyParameter</DisplayName>
    <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
    <Metadata>
        <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
    </Metadata>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="myParameter" AlwaysUseDefaultValue="true" DefaultValue="{OAUTH-KV:myparameter}" />
    </OutputClaims>
  </TechnicalProfile>

Then run that profile in an OrchestrationStep before the claim value is required (it can be the first one or somewhere later along the way, doesn't matter much as far as I can tell).

You can have as many parameters in the technical profile as you wish. Works every time, doesn't crash if you don't provide value.

Solution 3:[3]

I Faced with the same problem, and found answer in official documentation

Don't forget to create claimType in your claims schema

<ClaimType Id="q_param">
            <DisplayName>q_param</DisplayName>
            <DataType>string</DataType>
            <UserHelpText>Special parameter passed for authentication context</UserHelpText>
        </ClaimType>

Additionally you need to set output claim in technical profile like in example from TrustFrameworkExtensions.xml

<ClaimsProvider>
        <DisplayName>Local Account SignIn</DisplayName>
        <TechnicalProfiles>
            <TechnicalProfile Id="login-NonInteractive">
                <Metadata>
                    <Item Key="client_id">ProxyIdentityExperienceFrameworkAppId</Item>
        <Item Key="IdTokenAudience">IdentityExperienceFrameworkAppId</Item>
                </Metadata>
                <InputClaims>
                     <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="ProxyIdentityExperienceFrameworkAppId" />
        <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="IdentityExperienceFrameworkAppId" />
                </InputClaims>
                <OutputClaims>
                    <OutputClaim ClaimTypeReferenceId="q_param" DefaultValue="{OAUTH-KV:q_param}" />
                </OutputClaims>                 
                <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
            </TechnicalProfile>
        </TechnicalProfiles>
    </ClaimsProvider>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jas Suri - MSFT
Solution 2 wojtekdo
Solution 3 FClon