Alternatively, you can create a validation technical profile, which encapsulates the attribute validation, that is executed by the account registration technical profile.
For example, you might have the following technical profile, which registers a local account with a social security number:
<TechnicalProfile Id="LocalAccount-Registration">
<DisplayName>Local Account Registration</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.localaccount.registration</Item>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="language.button_continue">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="displayName" Required="true" />
<OutputClaim ClaimTypeReferenceId="extension_SocialSecurityNumber" Required="true" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="newUser" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="sub" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AzureFunctions-CheckCustomer" />
<ValidationTechnicalProfile ReferenceId="AzureActiveDirectoryStore-WriteUserByEmail-ThrowIfExists" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SSOSession-AzureActiveDirectory" />
</TechnicalProfile>
The first validation technical profile called "AzureFunctions-CheckCustomer", which is executed when the end user submits the registration form, invokes an Azure Function (or other external service) to validate the registration fields.
<TechnicalProfile Id="AzureFunctions-CheckCustomer">
<DisplayName>Check Customer Azure Function</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://contoso.azurewebsites.net/api/CheckCustomer?code=...</Item>
<Item Key="AuthenticationType">None</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="extension_SocialSecurityNumber" PartnerClaimType="socialSecurityNumber" />
</InputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SSOSession-Noop" />
</TechnicalProfile>
If the Azure Function returns 200 OK, then the next validation technical profile called "AzureActiveDirectoryStore-WriteUserByEmail-ThrowIfExists" creates the local account and the end user can continue to the next step. If the Azure Function returns 409 Conflict with an error message, then the local account is not created and the error message is displayed to the end user.