0
votes

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>
1
Have you tried debugging the issue with Application Insights? If you setup the app insights journey recorder, you can check what claims are being passed between steps.juunas
Good idea, I reviewed the logs and looks like the name claims are not even being extracted from the token. They other claims (email and testclaim1) are being extracted and added to the claims bag.ToDevAndBeyond
@ToDevAndBeyond Any update for this issue?Tony Ju
@TonyJu, I didn't figure out the underlying issue, but I just posted my workaround belowToDevAndBeyond

1 Answers

0
votes

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>