B2C Custom policy - Claims from SelfAsserted TP do not get persisted to B2C user store

Kai Biefang 21 Reputation points
2022-11-24T14:56:16.003+00:00

Hello, I'm having trouble persisting custom attributes in the B2C user store.

I have added the relevant custom attributes ("PermissionUserView" in my example) via Azure portal and have defined ClaimTypes in the ClaimsSchema of the Extension policy.

I created a custom sign up form with a SelfAsserted technical profile, which should not display input for the custom claim, but always provide a default value. For this, the ClaimType has no UserInputType defined and I added an OutputClaim to the SelfAsserted TP with a DefaultValue and AlwaysUseDefaultValue set to true. The SelfAsserted TP uses a ValidationTechnicalProfile to save the user input to the B2C user store.

When the token gets issued, I can see the correct value for the custom claim. But it does not get persisted in the user store. When I query the claim via Graph or use a policy to log in, the claim is not there.

Custom claim Definition:

  <ClaimType Id="extension_PermissionUserView">  
    <DisplayName>Permission to view users</DisplayName>  
    <DataType>boolean</DataType>  
  </ClaimType>  

SelfAsserted TP in Extensions policy (custom sign up form with default value for custom claim):

<TechnicalProfile Id="CustomLocalAccountSignUpWithLogonEmail">  
  <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>  
  </Metadata>  
  <CryptographicKeys>  
    <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />  
  </CryptographicKeys>  
  <InputClaims>  
    <InputClaim ClaimTypeReferenceId="email" />  
  </InputClaims>  
  <OutputClaims>  
    <OutputClaim ClaimTypeReferenceId="objectId" />  
    <OutputClaim ClaimTypeReferenceId="email" 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" />  
  
    <OutputClaim ClaimTypeReferenceId="givenName" />  
    <OutputClaim ClaimTypeReferenceId="surName" />  
  
    <!-- Custom claim with default value. Does not get displayed because UserInputType is not defined -->  
    <OutputClaim ClaimTypeReferenceId="extension_PermissionUserView" DefaultValue="true" AlwaysUseDefaultValue="true" />  
  
  </OutputClaims>  
  <ValidationTechnicalProfiles>  
    <ValidationTechnicalProfile ReferenceId="BuildDisplayName" /> <!-- Builds displayName from given and surname -->  
    <ValidationTechnicalProfile ReferenceId="REST-AcquireAccessToken" /> <!-- Aquires token from AD for subsequent call -->  
    <ValidationTechnicalProfile ReferenceId="REST-GenerateTenantId" /> <!-- Generates another custom claim. This gets persisted correctly -->  
    <ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />  
  </ValidationTechnicalProfiles>  
  <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />  
</TechnicalProfile>  

AAD technical profile to save additional claims in Extensions policy (merges with TP from Base policy):

<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">  
  <PersistedClaims>  
    <PersistedClaim ClaimTypeReferenceId="extension_appTenantId" />  
  
    <PersistedClaim ClaimTypeReferenceId="extension_PermissionUserView" />  
      
  </PersistedClaims>  
</TechnicalProfile>  

As you can see, the validation TP "REST-GenerateTenantId", which gets called by the SelfAsserted TP has another custom claim "extension_appTenantId" as OutputClaim, which gets persisted correctly. The custom claim "extension_PermissionUserView" from the SelfAsserted TP does not get persisted.

Where is my error here?

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,759 questions
0 comments No comments
{count} votes

Accepted answer
  1. Akshay-MSFT 17,656 Reputation points Microsoft Employee
    2022-11-29T07:58:27.3+00:00

    Hello @Kai Biefang ,

    Thank you for posting your query on Microsoft Q&A. I was able to review this and found that within claims schema ClaimType Id="extension_PermissionUserView" you must specify the UserInputType when you collect information from the user by using a self-asserted technical profile. Ref: https://learn.microsoft.com/bs-latn-ba/azure/active-directory-b2c/claimsschema#userinputtype

    You need to reference the TechnicalProfiles for CustomLocalAccountSignUpWithLogonEmail from your SignUpOrSignin.xml. You can also have two versions of TechnicalProfiles for CustomLocalAccountSignUpWithLogonEmail and AAD-UserWriteUsingLogonEmail in the Base policy file. One accepts user input, and the other one sets DefaultValue for your custom claim.

    As confirmed by you if you want to avoid user input then workaround could be:

    Adding the OutputClaims to the validation technical profile which is running before the "AAD-UserWriteUsingLogonEmail" VTP which persists the data.

    Please do let me know if you have any queries in the comments section.

    Thanks,
    Akshay Kaushik

    Please "Accept the answer", "Upvote" and rate your experience if the suggestion works as per your business need. This will help us and others in the community as well.


0 additional answers

Sort by: Most helpful