question

LockTar avatar image
4 Votes"
LockTar asked LockTar edited

ClaimsTransformation array of objects raises empty body

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?

azure-ad-b2c
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@amanpreetsingh-msft do you have an idea for this problem???

0 Votes 0 ·

Hi @LockTar · I have never tried this. I will check with my team if they can suggest a better way to achieve this.

0 Votes 0 ·
yoelhor avatar image
0 Votes"
yoelhor answered LockTar edited
  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.



· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

See my new answer of yesterday aug 16. I created a new solution that is much simpler! Thank you for the support and updating the documentation. This is now much clearer and crucial in situation!

0 Votes 0 ·
LockTar avatar image
0 Votes"
LockTar answered LockTar edited

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...

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

See my answer of aug 16 2022 (can't mark as answer...) for a better and simpler workaround after working with the B2C Product Group of Microsoft.

0 Votes 0 ·
yoelhor avatar image
1 Vote"
yoelhor answered LockTar commented

Dear @LockTar,

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

· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

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.


I'm not sure what you mean with this. Can you elaborate this a bit? Is there an easier workaround?

It's also a bit strange that if you combine input parameters and input claims in a JSON array you will get a complete empty body. Not an error or not complete json body but no json body at all... Sounds to me as a bug.

0 Votes 0 ·

I see that you used the GetClaimsFromKeyValueJson to set values to the claims that were before input parameters. All I say that you don't need to use a claims transformation. In the SendOtp technical profile you can add inputClaims with default values (for the input parameters that have need converted to claims). You solution is great, and this is the best workaround.

0 Votes 0 ·

Sorry I really think I miss something... Could you please help me? I'm trying to understand. Sounds to me it's very obvious but I don't see it...

0 Votes 0 ·
yoelhor avatar image
0 Votes"
yoelhor answered DanielOsorio-2120 Suspended commented

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>


· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

So I tried this code but it doesn't work. I've added all input claims. I understand the idea and I like it because it is simple and easier to maintain.

The thing is that you can't have two "InputClaims" elements so I combined them into one. I also disabled/removed InputClaimsTransformation "GenerateKeyValueJsonForClaims" and "GetClaimsFromKeyValueJson" because they are replaced by the 9 new input claims. I send the output to a request bin for easy debug. The correct rest call is send but the B2C userinterface displays and error: "There is an error performing the operation.". No input textbox for the verification code is shown. How can I get the real error because I can't find anything in application insights.

0 Votes 0 ·
LockTar avatar image
3 Votes"
LockTar answered LockTar published

@yoelhor 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!

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.