'Is it possible to automatically update B2C user details by using claims from the Issuer, using Identity Experience Framework?

I have created a policy for an application following the B2C tutorial docs. It successfully creates users in a B2C tenant, filling in givename.. email etc from any/all issuers - currently, other any other Azure tenant can sign into this B2C tenant, this is what is required.

But what if details change with the original issuer's object (a name change, for example)? Currently there would be a mismatch, unless the user follows a journey to edit their own profile (manually).

Would it be possible to create a journey which asks for claims from the issuer AFTER the object exists in the B2C tenant, and then update the local user with new details?

The result I was looking to achieve was an automatic update to the the B2C tenant user, if the original account has been edited in some way, at the point the B2C user authenticates. And that way the application linked to the B2C Tenant could be sent the updated claims.

I understand the premise, but what I am lacking is the knowledge of what steps in a journey I would need, what these steps would look like. If anyone could share an example of even just reading a Name from the orginal issuer, and copying it the B2C tenent user, it would be extremely useful to me.

[Edit] Thanks to Jas for the detailed solution! I solved this by simply adding a AAD-UserReadUsingObjectId and a AAD-UserWriteUsingAlternativeSecurityId steps to the end of the signup-sign in journey. Which updates the B2C User object with claims from the original object every time they login, and meets the requirements since it updates the B2C tenant and passes the updated attributes to the application which requires them too.



Solution 1:[1]

Output claims in the OpenId technical profile allow you to map claims incoming from the IdP into the AAD B2C claimbag.

Lets use the example of monitoring whether displayName has changed at the IdP.

<OutputClaims>
  <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="live.com" />
  <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />
  <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="sub" />
  <OutputClaim ClaimTypeReferenceId="displayNameFromIdp" PartnerClaimType="name" />
  <OutputClaim ClaimTypeReferenceId="email" />
</OutputClaims>

Then we read the user using AAD-ReadUsingAlternativeSecurityId, by default. See the output claims here as follows, this will read the displayName of the user that already exists in B2C directory.

          <OutputClaims>
            <!-- Required claims -->
            <OutputClaim ClaimTypeReferenceId="objectId" />

            <!-- Optional claims -->
            <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
            <OutputClaim ClaimTypeReferenceId="displayName" />
            <OutputClaim ClaimTypeReferenceId="otherMails" />
            <OutputClaim ClaimTypeReferenceId="givenName" />
            <OutputClaim ClaimTypeReferenceId="surname" />
            <OutputClaim ClaimTypeReferenceId="identityChanged" DefaultValue="false"/>
          </OutputClaims>

Now, we compare the displayName and displayNameFromIdp values using CompareClaims claim transform.

<ClaimsTransformation Id="CompareDisplayName" TransformationMethod="CompareClaims">
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="displayNameFromIdp" TransformationClaimType="inputClaim1" />
    <InputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="inputClaim2" />
  </InputClaims>
  <InputParameters>
    <InputParameter Id="operator" DataType="string" Value="NOT EQUAL" />
    <InputParameter Id="ignoreCase" DataType="boolean" Value="true" />
  </InputParameters>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="identityChanged" TransformationClaimType="outputClaim" />
  </OutputClaims>
</ClaimsTransformation>

Make a claim transform like this for each claim you want to check. Only change the inputClaims, so if anything changes, it's always reflected as a boolean in identityChanged claim.

Add this claimTransform as an output claims transform to AAD-ReadUsingAlternativeSecurityId:

          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CompareDisplayName" />
          </OutputClaimsTransformations>

For each claim transform you create, for each attribute you want to keep sync'd, add an output claims transform referencing the claim transformation id.

Now, if identityChanged == true, we know to call the AAD Write technical profile. In your journey, add a step, at some point after AAD-UserReadUsingAlternativeSecurityId (after reading the user), and after AAD-UserWriteUsingAlternativeSecurityId (after creating the user).

        <OrchestrationStep Order="NUMBER" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>identityChanged</Value>
              <Value>false</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserUpdate" TechnicalProfileReferenceId="AAD-UserUpdateUsingAlternativeSecurityId" />
          </ClaimsExchanges>
        </OrchestrationStep>

Define an Azure AD technical profile to update the user:

        <TechnicalProfile Id="AAD-UserUpdateUsingAlternativeSecurityId">
          <Metadata>
            <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
          </Metadata>
          <PersistedClaims>
            <PersistedClaim ClaimTypeReferenceId="alternativeSecurityId" />
          </PersistedClaims>
          <IncludeTechnicalProfile ReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
        </TechnicalProfile>

Define a claim identityChanged, and displayNameFromIdp:

      <ClaimType Id="identityChanged">
        <DisplayName>identityChanged</DisplayName>
        <DataType>boolean</DataType>
      </ClaimType>
      <ClaimType Id="displayNameFromIdp">
        <DisplayName>displayNameFromIdp</DisplayName>
        <DataType>string</DataType>
      </ClaimType>

Solution 2:[2]

The flow would be:

  • User logs in
  • Call the original issuer via API and get the user's latest details
  • Compare details and update if required. You can use the string transformations.
  • Write the updated details

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
Solution 2 rbrayb