Saturday, February 3, 2024

Azure AD B2C: Validating Output Claim from a Non-Self-Asserted Technical Profile

I had a requirement where I wanted to do an additional validation on a boolean claim value in an AAD B2C user journey. If the boolean claim value is true, I wanted to move forward in the user journey. If the value is false, I wanted to short circuit the user journey and return an error. 

I couldn't use Validation Technical Profiles, because the output claim I am validating upon was in a non-self-asserted technical profile (the claim was retrieved by calling an external REST endpoint)  and Validation Technical Profiles doesn't support non-self-asserted technical profiles.

In such cases, we can add an additional OrchestrationStep, do a Precondition in that particular step, assert and navigate the user to a self-asserted technical profile and display the error there.

So how do we do that? 

1. Define a ClaimType for a self-asserted technical profile.

<BuildingBlocks>
  <ClaimsSchema>
    ...
    <ClaimType Id="errorMessage">
      <DisplayName>Please contact support.</DisplayName>
      <DataType>string</DataType>
      <UserInputType>Paragraph</UserInputType>
    </ClaimType>
  </ClaimsSchema>
  ...
</BuildingBlocks>

2. Define a ClaimsTransformation.

<BuildingBlocks>
  ...
  <ClaimsTransformations> ...
    <ClaimsTransformation Id="CreateApplicationUserNotActiveErrorMessage" TransformationMethod="CreateStringClaim">
      <InputParameters>
        <InputParameter Id="value" DataType="string" Value="Application user is not active." />
      </InputParameters>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="errorMessage" TransformationClaimType="createdClaim" />
      </OutputClaims>
    </ClaimsTransformation>
  </ClaimsTransformations>
</BuildingBlocks>

3. Define a self-asserted TechnicalProfile. Use the above ClaimsTransformation as a InputClaimsTransformation. Reference the ClaimType created in the first step.

<ClaimsProviders>
  <ClaimsProvider>
    <DisplayName>...</DisplayName>
    <TechnicalProfiles> ...
      <TechnicalProfile Id="SelfAsserted-ApplicationUserNotActiveError">
        <DisplayName>Error message</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="setting.showContinueButton">false</Item>
          <Item Key="setting.showCancelButton">true</Item>
        </Metadata>
        <InputClaimsTransformations>
          <InputClaimsTransformation ReferenceId="CreateApplicationUserNotActiveErrorMessage" />
        </InputClaimsTransformations>
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="errorMessage"/>
        </InputClaims>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="errorMessage"/>
        </OutputClaims>
      </TechnicalProfile>
    </TechnicalProfiles>
  </ClaimsProvider>
</ClaimsProviders>

4. Introduce an additional OrchestrationStep with a Precondition before the last the OrchestrationStep. If the condition is not satisfied, use the created self-asserted TechnicalProfile.

<UserJourneys>
  ...
  <UserJourney Id="...">
    <OrchestrationSteps>
      ...
      <OrchestrationStep Order="9" Type="ClaimsExchange">
        <Preconditions>
          <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
            <Value>isActive</Value> <!-- this claim is forwarded from a previous step -->
            <Value>True</Value>
            <Action>SkipThisOrchestrationStep</Action>
          </Precondition>
        </Preconditions>
        <ClaimsExchanges>
          <ClaimsExchange Id="SelfAssertedApplicationUserNotActiveError" TechnicalProfileReferenceId="SelfAsserted-ApplicationUserNotActiveError" />
        </ClaimsExchanges>
      </OrchestrationStep>
      ...
      <OrchestrationStep Order="11" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
    </OrchestrationSteps>
  </UserJourney>
  ...
</UserJourneys>

And this is what happens when isActive claim is false. When it's true, the above OrchestrationStep will get skipped and the user journey will continue.
Self-Asserted Technical Profile
Hope this helps.

Happy Coding.

Regards,
Jaliya

No comments:

Post a Comment