ClaimsTransformation array of objects raises empty body

Ralph Jansen 106 Reputation points
2022-04-11T09:06:15.41+00:00

Hi,

I'm required to use an API for sending the email with the OTP. The API has a specific JSON body like so:

{
  "reference": "a5747a9c-3124-4ffc-b031-e1db5726950a", // Unique id from client
  "sender": { 
    "emailSubject": "example account email verification code", 
    "emailReplyTo": "noreply@example.com", 
    "emailFrom": "noreply@example.com", 
    "emailFromName": "example"
  },
  "letterId": "AccountValidation", // do not change this. This is unqiue for Azure B2C
  "ReplyToQueue": "",
  "receiver": {
    "emailTo": "example@example.com"
  },
  "letterVariables": [
    {
      "name": "numberAttachments",
      "value": "0"
    },
    {
      "name": "title",
      "value": "Verify your email address"
    },
    {
      "name": "salutation",
      "value": "Dear"
    },
    {
      "name": "message",
      "value": "Thanks for validating the account"
    },
    {
      "name": "codeIntro",
      "value": "Your code is"
    },
    {
      "name": "otp",
      "value": "871400"
    },
    {
      "name": "signature",
      "value": "Sincerely"
    },
    {
      "name": "footer",
      "value": "This is an automatic generated message from example. Don't reply to this email."
    }
  ]
}

The important part is the "letterVariables" array of objects.

If I use the following transformation I get an empty body:

<ClaimsTransformation Id="GenerateEmailRequestBody" TransformationMethod="GenerateJson">
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="uniqueEmailReference" TransformationClaimType="reference" />
        <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="receiver.emailTo" />
        <InputClaim ClaimTypeReferenceId="subject" TransformationClaimType="sender.emailSubject" />

        <InputClaim ClaimTypeReferenceId="title" TransformationClaimType="letterVariables.1.value" />
        <InputClaim ClaimTypeReferenceId="salutation" TransformationClaimType="letterVariables.2.value" />
        <InputClaim ClaimTypeReferenceId="message" TransformationClaimType="letterVariables.3.value" />
        <InputClaim ClaimTypeReferenceId="codeIntro" TransformationClaimType="letterVariables.4.value" />
        <InputClaim ClaimTypeReferenceId="otp" TransformationClaimType="letterVariables.5.value" />
        <InputClaim ClaimTypeReferenceId="signature" TransformationClaimType="letterVariables.6.value" />
        <InputClaim ClaimTypeReferenceId="footer" TransformationClaimType="letterVariables.7.value" />
    </InputClaims>
    <InputParameters>
        <InputParameter Id="letterId" DataType="string" Value="AccountValidation" />
        <InputParameter Id="ReplyToQueue" DataType="string" Value="" />
        <InputParameter Id="sender.emailReplyTo" DataType="string" Value="noreply@example.com" />
        <InputParameter Id="sender.emailFrom" DataType="string" Value="noreply@example.com" />
        <InputParameter Id="sender.emailFromName" DataType="string" Value="Example" />
        <InputParameter Id="letterVariables.0.name" DataType="string" Value="numberAttachments" />
        <InputParameter Id="letterVariables.0.value" DataType="string" Value="0" />
        <InputParameter Id="letterVariables.1.name" DataType="string" Value="title" />
        <InputParameter Id="letterVariables.2.name" DataType="string" Value="salutation" />
        <InputParameter Id="letterVariables.3.name" DataType="string" Value="message" />
        <InputParameter Id="letterVariables.4.name" DataType="string" Value="codeIntro" />
        <InputParameter Id="letterVariables.5.name" DataType="string" Value="otp" />
        <InputParameter Id="letterVariables.6.name" DataType="string" Value="signature" />
        <InputParameter Id="letterVariables.7.name" DataType="string" Value="footer" />
    </InputParameters>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="emailRequestBody" TransformationClaimType="outputClaim" />
    </OutputClaims>
</ClaimsTransformation>

This generates an empty body and throws an exception without any details. Just with trial and error I found out that mixing the order of letterVariables child objects between InputParameter and InputClaim causes this.
So what does work is in example is:

<ClaimsTransformation Id="GenerateEmailRequestBody" TransformationMethod="GenerateJson">
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="uniqueEmailReference" TransformationClaimType="reference" />
        <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="receiver.emailTo" />
        <InputClaim ClaimTypeReferenceId="subject" TransformationClaimType="sender.emailSubject" />

        <!-- <InputClaim ClaimTypeReferenceId="title" TransformationClaimType="letterVariables.1.value" />
        <InputClaim ClaimTypeReferenceId="salutation" TransformationClaimType="letterVariables.2.value" />
        <InputClaim ClaimTypeReferenceId="message" TransformationClaimType="letterVariables.3.value" />
        <InputClaim ClaimTypeReferenceId="codeIntro" TransformationClaimType="letterVariables.4.value" />
        <InputClaim ClaimTypeReferenceId="otp" TransformationClaimType="letterVariables.5.value" />
        <InputClaim ClaimTypeReferenceId="signature" TransformationClaimType="letterVariables.6.value" />
        <InputClaim ClaimTypeReferenceId="footer" TransformationClaimType="letterVariables.7.value" /> -->
    </InputClaims>
    <InputParameters>
        <InputParameter Id="letterId" DataType="string" Value="AccountValidation" />
        <InputParameter Id="ReplyToQueue" DataType="string" Value="" />
        <InputParameter Id="sender.emailReplyTo" DataType="string" Value="noreply@example.com" />
        <InputParameter Id="sender.emailFrom" DataType="string" Value="noreply@example.com" />
        <InputParameter Id="sender.emailFromName" DataType="string" Value="Example" />
        <InputParameter Id="letterVariables.0.name" DataType="string" Value="numberAttachments" />
        <InputParameter Id="letterVariables.0.value" DataType="string" Value="0" />
        <InputParameter Id="letterVariables.1.name" DataType="string" Value="title" />
        <InputParameter Id="letterVariables.2.name" DataType="string" Value="salutation" />
        <InputParameter Id="letterVariables.3.name" DataType="string" Value="message" />
        <InputParameter Id="letterVariables.4.name" DataType="string" Value="codeIntro" />
        <InputParameter Id="letterVariables.5.name" DataType="string" Value="otp" />
        <InputParameter Id="letterVariables.6.name" DataType="string" Value="signature" />
        <InputParameter Id="letterVariables.7.name" DataType="string" Value="footer" />
    </InputParameters>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="emailRequestBody" TransformationClaimType="outputClaim" />
    </OutputClaims>
</ClaimsTransformation>

This generates of course all child objects but only with the name property.

Or what also works is this:

<ClaimsTransformation Id="GenerateEmailRequestBody" TransformationMethod="GenerateJson">
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="uniqueEmailReference" TransformationClaimType="reference" />
        <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="receiver.emailTo" />
        <InputClaim ClaimTypeReferenceId="subject" TransformationClaimType="sender.emailSubject" />

        <InputClaim ClaimTypeReferenceId="title" TransformationClaimType="letterVariables.0.value" />
        <InputClaim ClaimTypeReferenceId="title" TransformationClaimType="letterVariables.1.value" />
        <InputClaim ClaimTypeReferenceId="salutation" TransformationClaimType="letterVariables.2.value" />
        <InputClaim ClaimTypeReferenceId="message" TransformationClaimType="letterVariables.3.value" />
        <InputClaim ClaimTypeReferenceId="codeIntro" TransformationClaimType="letterVariables.4.value" />
        <InputClaim ClaimTypeReferenceId="otp" TransformationClaimType="letterVariables.5.value" />
        <InputClaim ClaimTypeReferenceId="signature" TransformationClaimType="letterVariables.6.value" />
        <InputClaim ClaimTypeReferenceId="footer" TransformationClaimType="letterVariables.7.value" />
    </InputClaims>
    <InputParameters>
        <InputParameter Id="letterId" DataType="string" Value="AccountValidation" />
        <InputParameter Id="ReplyToQueue" DataType="string" Value="" />
        <InputParameter Id="sender.emailReplyTo" DataType="string" Value="noreply@example.com" />
        <InputParameter Id="sender.emailFrom" DataType="string" Value="noreply@example.com" />
        <InputParameter Id="sender.emailFromName" DataType="string" Value="Example" />
        <!-- <InputParameter Id="letterVariables.0.name" DataType="string" Value="numberAttachments" />
        <InputParameter Id="letterVariables.0.value" DataType="string" Value="0" />
        <InputParameter Id="letterVariables.1.name" DataType="string" Value="title" />
        <InputParameter Id="letterVariables.2.name" DataType="string" Value="salutation" />
        <InputParameter Id="letterVariables.3.name" DataType="string" Value="message" />
        <InputParameter Id="letterVariables.4.name" DataType="string" Value="codeIntro" />
        <InputParameter Id="letterVariables.5.name" DataType="string" Value="otp" />
        <InputParameter Id="letterVariables.6.name" DataType="string" Value="signature" />
        <InputParameter Id="letterVariables.7.name" DataType="string" Value="footer" /> -->
    </InputParameters>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="emailRequestBody" TransformationClaimType="outputClaim" />
    </OutputClaims>
</ClaimsTransformation>

This will only generate the value properties of the child objects.

So there is no way to combine InputParameters and InputClaims. I think this is a bug. There is no log or anything about it in application insights....

Any workaround for this?

Microsoft Entra External ID
Microsoft Entra External ID
A modern identity solution for securing access to customer, citizen and partner-facing apps and services. It is the converged platform of Azure AD External Identities B2B and B2C. Replaces Azure Active Directory External Identities.
2,652 questions
{count} votes

Accepted answer
  1. Yoel Hor 81 Reputation points Microsoft Employee
    2022-08-11T05:07:54.82+00:00
    1. The document has been updated with guidance how to use JSON arrays. In the first sample you have sent, the input claims starts with 1, while it must start with 0.
    2. Sorry for the duplicated input claims, my mistake (the second one should be output claims).
    3. The best and easiest solution in your case: use only input claims. Convert the static claims (input parameters) to dynamic ones (input claims). Then before you call the claims transformation, set default values to the claims that you converted.

4 additional answers

Sort by: Most helpful
  1. Ralph Jansen 106 Reputation points
    2022-08-16T16:10:36.357+00:00

    @Yoel Hor thank you for updating the docs!

    The following part of the updated documentation is crucial in my case:
    *To specify a JSON array in both the input claims and the input parameters, you must start the array in the InputClaims element, zero to N. Then, in the InputParameters element continue the index from the last index.

    The following example demonstrates an array that is defined in both the input claims and the input parameters. The first item of the values array values.0 is defined in the input claims. The input parameters continue from index one values.1 through two index values.2.*

    I need to mix values with static and dynamic values what is not possible in my case (your third bullet).

    Luckily there is a workaround for this. My original workaround works but is difficult and a lot of code. Your post confirms that I could only use “Input claims” in my case.

    I found an easier way for creating the static claims that is not really clear in the docs but it's there.

    So my solution is now:
    Create claims

    <ClaimType Id="letterVariablesNumberAttachmentsName">  
        <DisplayName>Claim for letters variables array default value</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesNumberAttachmentsValue">  
        <DisplayName>Claim for letters variables array default value</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesTitleName">  
        <DisplayName>Claim for letters variables array default value</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesSalutationName">  
        <DisplayName>Claim for letters variables array default value</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesMessageName">  
        <DisplayName>Claim for letters variables array default value</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesCodeIntroName">  
        <DisplayName>Claim for letters variables array default value</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesOtpName">  
        <DisplayName>Claim for letters variables array default value</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesSignatureName">  
        <DisplayName>Claim for letters variables array default value</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesFooterName">  
        <DisplayName>Claim for letters variables array default value</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    

    Create a new technical profile that will fill the claims with static values (I think this is the best way unless you have a better way).

    <TechnicalProfile Id="CreateInputClaimsForBody">  
        <DisplayName>Create input claims with static values for letterVariables array in the body</DisplayName>  
        <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />  
        <OutputClaims>  
            <OutputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsName" DefaultValue="numberAttachments" AlwaysUseDefaultValue="true" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsValue" DefaultValue="0" AlwaysUseDefaultValue="true" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesTitleName" DefaultValue="title" AlwaysUseDefaultValue="true" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesSalutationName" DefaultValue="salutation" AlwaysUseDefaultValue="true" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesMessageName" DefaultValue="message" AlwaysUseDefaultValue="true" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesCodeIntroName" DefaultValue="codeIntro" AlwaysUseDefaultValue="true" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesOtpName" DefaultValue="otp" AlwaysUseDefaultValue="true" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesSignatureName" DefaultValue="signature" AlwaysUseDefaultValue="true" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesFooterName" DefaultValue="footer" AlwaysUseDefaultValue="true" />  
        </OutputClaims>  
    </TechnicalProfile>  
    

    Call the new technical profile CreateInputClaimsForBody before sending the otp (creating the email body and sending) with technical profile SendOtp

    <Action Id="SendCode">  
                <ValidationClaimsExchange>  
                  <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="AAD-CheckEmailAddressExists" />  
                  <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="GenerateOtp" />  
                  <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="REST-AcquireAccessToken" />  
                  <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="CreateInputClaimsForBody" />  
                  <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="SendOtp">  
                    <Preconditions>  
                      <Precondition Type="ClaimsExist" ExecuteActionsIf="false">  
                        <Value>objectId</Value>  
                        <Action>SkipThisValidationTechnicalProfile</Action>  
                      </Precondition>  
                    </Preconditions>  
                  </ValidationClaimsExchangeTechnicalProfile>  
                </ValidationClaimsExchange>  
              </Action>  
    

    Generate the email body array with only input claims because I need to use static values and dynamic values. I can still use other input parameters for static values but they are not in the array.

    <ClaimsTransformation Id="GenerateEmailRequestBody" TransformationMethod="GenerateJson">  
            <InputClaims>  
              <InputClaim ClaimTypeReferenceId="uniqueEmailReference" TransformationClaimType="reference" />  
              <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="receiver.emailTo" />  
              <InputClaim ClaimTypeReferenceId="subject" TransformationClaimType="sender.emailSubject" />  
      
              <InputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsName" TransformationClaimType="letterVariables.0.name" />  
              <InputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsValue" TransformationClaimType="letterVariables.0.value" />  
              <InputClaim ClaimTypeReferenceId="letterVariablesTitleName" TransformationClaimType="letterVariables.1.name" />  
              <InputClaim ClaimTypeReferenceId="title" TransformationClaimType="letterVariables.1.value" />  
              <InputClaim ClaimTypeReferenceId="letterVariablesSalutationName" TransformationClaimType="letterVariables.2.name" />  
              <InputClaim ClaimTypeReferenceId="salutation" TransformationClaimType="letterVariables.2.value" />  
              <InputClaim ClaimTypeReferenceId="letterVariablesMessageName" TransformationClaimType="letterVariables.3.name" />  
              <InputClaim ClaimTypeReferenceId="message" TransformationClaimType="letterVariables.3.value" />  
              <InputClaim ClaimTypeReferenceId="letterVariablesCodeIntroName" TransformationClaimType="letterVariables.4.name" />  
              <InputClaim ClaimTypeReferenceId="codeIntro" TransformationClaimType="letterVariables.4.value" />  
              <InputClaim ClaimTypeReferenceId="letterVariablesOtpName" TransformationClaimType="letterVariables.5.name" />  
              <InputClaim ClaimTypeReferenceId="otp" TransformationClaimType="letterVariables.5.value" />  
              <InputClaim ClaimTypeReferenceId="letterVariablesSignatureName" TransformationClaimType="letterVariables.6.name" />  
              <InputClaim ClaimTypeReferenceId="signature" TransformationClaimType="letterVariables.6.value" />  
              <InputClaim ClaimTypeReferenceId="letterVariablesFooterName" TransformationClaimType="letterVariables.7.name" />  
              <InputClaim ClaimTypeReferenceId="footer" TransformationClaimType="letterVariables.7.value" />  
            </InputClaims>  
            <InputParameters>  
              <InputParameter Id="letterId" DataType="string" Value="ExampleId" />  
              <InputParameter Id="ReplyToQueue" DataType="string" Value="" />  
              <InputParameter Id="sender.emailReplyTo" DataType="string" Value=noreply@example.net />  
              <InputParameter Id="sender.emailFrom" DataType="string" Value=noreply@example.net />  
              <InputParameter Id="sender.emailFromName" DataType="string" Value="Example" />  
            </InputParameters>  
            <OutputClaims>  
              <OutputClaim ClaimTypeReferenceId="emailRequestBody" TransformationClaimType="outputClaim" />  
            </OutputClaims>  
          </ClaimsTransformation>  
    

    Hopefully this will help someone in the future!

    4 people found this answer helpful.
    0 comments No comments

  2. Yoel Hor 81 Reputation points Microsoft Employee
    2022-04-18T17:52:06.813+00:00

    Dear @Ralph Jansen ,

    You are right, it's not supported to combine input parameters and input claims in a JSON array. Your insights and the workaround are valuable. It's the best way to solve this issue. Convert the relevant input parameters (the one that under the letter variables array) into input claims.

    I'm not sure why you need the extra claims transformation. In the SendOtp technical profile you can set the value as input claims with defaultValue. Anyway the idea is the same, convert the input parameters into claims and set their values.

    Yoel

    1 person found this answer helpful.

  3. Ralph Jansen 106 Reputation points
    2022-04-11T14:45:18.277+00:00

    See my answer of aug 16 for a much better solution after discussing with Microsoft!

    I created a workaround that is clearly not ideal....

    Create some extra claimtypes:

    <ClaimType Id="keyValueJsonForClaimsForEmailBody">  
        <DisplayName>Temp workaround generate json with key value pairs</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesNumberAttachmentsName">  
        <DisplayName>Temp workaround claim</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesNumberAttachmentsValue">  
        <DisplayName>Temp workaround claim</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesTitleName">  
        <DisplayName>Temp workaround claim</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesSalutationName">  
        <DisplayName>Temp workaround claim</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesMessageName">  
        <DisplayName>Temp workaround claim</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesCodeIntroName">  
        <DisplayName>Temp workaround claim</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesOtpName">  
        <DisplayName>Temp workaround claim</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesSignatureName">  
        <DisplayName>Temp workaround claim</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    <ClaimType Id="letterVariablesFooterName">  
        <DisplayName>Temp workaround claim</DisplayName>  
        <DataType>string</DataType>  
    </ClaimType>  
    

    Generate a key value pair array with as value the "fixed" data that later is needed as the "name" value of the "letterVariables" array.

    <ClaimsTransformation Id="GenerateKeyValueJsonForClaims" TransformationMethod="GenerateJson">  
        <InputParameters>  
          <InputParameter Id="0.key" DataType="string" Value="letterVariablesNumberAttachmentsName" />  
          <InputParameter Id="0.value" DataType="string" Value="numberAttachments" />  
          <InputParameter Id="1.key" DataType="string" Value="letterVariablesNumberAttachmentsValue" />  
          <InputParameter Id="1.value" DataType="string" Value="0" />  
          <InputParameter Id="2.key" DataType="string" Value="letterVariablesTitleName" />  
          <InputParameter Id="2.value" DataType="string" Value="title" />  
          <InputParameter Id="3.key" DataType="string" Value="letterVariablesSalutationName" />  
          <InputParameter Id="3.value" DataType="string" Value="salutation" />  
          <InputParameter Id="4.key" DataType="string" Value="letterVariablesMessageName" />  
          <InputParameter Id="4.value" DataType="string" Value="message" />  
          <InputParameter Id="5.key" DataType="string" Value="letterVariablesCodeIntroName" />  
          <InputParameter Id="5.value" DataType="string" Value="codeIntro" />  
          <InputParameter Id="6.key" DataType="string" Value="letterVariablesOtpName" />  
          <InputParameter Id="6.value" DataType="string" Value="otp" />  
          <InputParameter Id="7.key" DataType="string" Value="letterVariablesSignatureName" />  
          <InputParameter Id="7.value" DataType="string" Value="signature" />  
          <InputParameter Id="8.key" DataType="string" Value="letterVariablesFooterName" />  
          <InputParameter Id="8.value" DataType="string" Value="footer" />  
        </InputParameters>  
        <OutputClaims>  
          <OutputClaim ClaimTypeReferenceId="keyValueJsonForClaimsForEmailBody" TransformationClaimType="outputClaim" />  
        </OutputClaims>  
      </ClaimsTransformation>  
    

    Then create an extra ClaimsTransformations that will fill the new claimtypes by extracting it from the key value pairs:

    <ClaimsTransformation Id="GetClaimsFromKeyValueJson" TransformationMethod="GetClaimsFromJsonArray">  
        <InputClaims>  
            <InputClaim ClaimTypeReferenceId="keyValueJsonForClaimsForEmailBody" TransformationClaimType="jsonSource" />  
        </InputClaims>  
        <InputParameters>  
            <InputParameter Id="errorOnMissingClaims" DataType="boolean" Value="true" />  
            <InputParameter Id="includeEmptyClaims" DataType="boolean" Value="true" />  
            <InputParameter Id="jsonSourceKeyName" DataType="string" Value="key" />  
            <InputParameter Id="jsonSourceValueName" DataType="string" Value="value" />  
        </InputParameters>  
        <OutputClaims>  
            <OutputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsName" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsValue" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesTitleName" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesSalutationName" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesMessageName" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesCodeIntroName" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesOtpName" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesSignatureName" />  
            <OutputClaim ClaimTypeReferenceId="letterVariablesFooterName" />  
        </OutputClaims>  
    </ClaimsTransformation>  
    

    Create a ClaimsTransformations that will generate the Json body only with InputClaims because we can't use both together:

    <ClaimsTransformation Id="GenerateEmailRequestBody" TransformationMethod="GenerateJson">  
        <InputClaims>  
            <InputClaim ClaimTypeReferenceId="uniqueEmailReference" TransformationClaimType="reference" />  
            <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="receiver.emailTo" />  
            <InputClaim ClaimTypeReferenceId="subject" TransformationClaimType="sender.emailSubject" />  
      
            <InputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsName" TransformationClaimType="letterVariables.0.name" />  
            <InputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsValue" TransformationClaimType="letterVariables.0.value" />  
            <InputClaim ClaimTypeReferenceId="letterVariablesTitleName" TransformationClaimType="letterVariables.1.name" />  
            <InputClaim ClaimTypeReferenceId="title" TransformationClaimType="letterVariables.1.value" />  
            <InputClaim ClaimTypeReferenceId="letterVariablesSalutationName" TransformationClaimType="letterVariables.2.name" />  
            <InputClaim ClaimTypeReferenceId="salutation" TransformationClaimType="letterVariables.2.value" />  
            <InputClaim ClaimTypeReferenceId="letterVariablesMessageName" TransformationClaimType="letterVariables.3.name" />  
            <InputClaim ClaimTypeReferenceId="message" TransformationClaimType="letterVariables.3.value" />  
            <InputClaim ClaimTypeReferenceId="letterVariablesCodeIntroName" TransformationClaimType="letterVariables.4.name" />  
            <InputClaim ClaimTypeReferenceId="codeIntro" TransformationClaimType="letterVariables.4.value" />  
            <InputClaim ClaimTypeReferenceId="letterVariablesOtpName" TransformationClaimType="letterVariables.5.name" />  
            <InputClaim ClaimTypeReferenceId="otp" TransformationClaimType="letterVariables.5.value" />  
            <InputClaim ClaimTypeReferenceId="letterVariablesSignatureName" TransformationClaimType="letterVariables.6.name" />  
            <InputClaim ClaimTypeReferenceId="signature" TransformationClaimType="letterVariables.6.value" />  
            <InputClaim ClaimTypeReferenceId="letterVariablesFooterName" TransformationClaimType="letterVariables.7.name" />  
            <InputClaim ClaimTypeReferenceId="footer" TransformationClaimType="letterVariables.7.value" />  
        </InputClaims>  
        <InputParameters>  
            <InputParameter Id="letterId" DataType="string" Value="AccountValidation" />  
            <InputParameter Id="ReplyToQueue" DataType="string" Value="" />  
            <InputParameter Id="sender.emailReplyTo" DataType="string" Value="noreply@example.com" />  
            <InputParameter Id="sender.emailFrom" DataType="string" Value="noreply@example.com" />  
            <InputParameter Id="sender.emailFromName" DataType="string" Value="Example" />  
        </InputParameters>  
        <OutputClaims>  
            <OutputClaim ClaimTypeReferenceId="emailRequestBody" TransformationClaimType="outputClaim" />  
        </OutputClaims>  
    </ClaimsTransformation>  
    

    And then use the transformations in the technicalprofile:

    <TechnicalProfile Id="SendOtp">  
        <DisplayName>Use  email API to send the code the the user</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://my-custom-api.com?subscription-key=blablabla</Item>  
            <Item Key="AuthenticationType">Bearer</Item>  
            <Item Key="SendClaimsIn">Body</Item>  
            <Item Key="ClaimUsedForRequestPayload">emailRequestBody</Item>  
            <Item Key="UseClaimAsBearerToken">bearerToken</Item>  
            <Item Key="DefaultUserMessageIfRequestFailed">Cannot process your request right now, please try again later.</Item>  
            <Item Key="DebugMode">true</Item>  
        </Metadata>  
        <InputClaimsTransformations>  
            <InputClaimsTransformation ReferenceId="CreateRandomEmailReference" />  
            <InputClaimsTransformation ReferenceId="GenerateKeyValueJsonForClaims" />  
            <InputClaimsTransformation ReferenceId="GetClaimsFromKeyValueJson" />  
            <InputClaimsTransformation ReferenceId="GenerateEmailRequestBody" />  
        </InputClaimsTransformations>  
        <InputClaims>  
            <InputClaim ClaimTypeReferenceId="bearerToken"/>  
            <InputClaim ClaimTypeReferenceId="emailRequestBody" />  
        </InputClaims>  
    </TechnicalProfile>  
    

    Hopefully someone has a better idea then this...


  4. Yoel Hor 81 Reputation points Microsoft Employee
    2022-04-28T18:21:36.657+00:00

    Nothing wrong with your policy. It looks good. There is another way to populate data into claim using the InputClaims. For example:

      <TechnicalProfile Id="SendOtp">
        <DisplayName>Use  email API to send the code the the user</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://my-custom-api.com?subscription-key=blablabla</Item>
            <Item Key="AuthenticationType">Bearer</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="ClaimUsedForRequestPayload">emailRequestBody</Item>
            <Item Key="UseClaimAsBearerToken">bearerToken</Item>
            <Item Key="DefaultUserMessageIfRequestFailed">Cannot process your request right now, please try again later.</Item>
            <Item Key="DebugMode">true</Item>
        </Metadata>
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsName"  DefaultValue="numberAttachments" />
          <InputClaim ClaimTypeReferenceId="letterVariablesNumberAttachmentsValue" DefaultValue="0" />
          <InputClaim ClaimTypeReferenceId="letterVariablesTitleName" DefaultValue="title" />
          <InputClaim ClaimTypeReferenceId="letterVariablesSalutationName" DefaultValue="salutation" />
          <!-- Add more here-->
        </InputClaims>
        <InputClaimsTransformations>
            <InputClaimsTransformation ReferenceId="CreateRandomEmailReference" />
            <InputClaimsTransformation ReferenceId="GenerateKeyValueJsonForClaims" />
            <InputClaimsTransformation ReferenceId="GetClaimsFromKeyValueJson" />
            <InputClaimsTransformation ReferenceId="GenerateEmailRequestBody" />
        </InputClaimsTransformations>
        <InputClaims>
            <InputClaim ClaimTypeReferenceId="bearerToken"/>
            <InputClaim ClaimTypeReferenceId="emailRequestBody" />
        </InputClaims>
    </TechnicalProfile>