I am trying to use the Sign up using invitation sample for B2C. We only want users to be able to sign up via invitation.
In my Entra B2C tenant, I have two User Attributes assigned:
- AdvisorId
- ClientId
I would like to persist these values on signup, and then return them as claims on sign in.
For my sign in user flow, I have already checked them to enable them as claims.
For generating my token, I have successfully added the claims and they look like this:
{
...
"name": "Johnny Test",
"https://schemas.mydomain.com/identity/advisorId": "12345",
"https://schemas.mydomain.com/identity/client/clientId": "67890"
}
The problem is on the redeem script. What I need it to do is, using the script from the example as a base, modify it so the incoming claims are saved to the user attributes.
Where I am
I have added definitions for my claim and the attribute:
<ClaimType Id="advisorId">
<DisplayName>User's Advisor Id</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OAuth2" PartnerClaimType="https://schemas.mydomain.com/identity/advisorId"/>
<Protocol Name="OpenIdConnect" PartnerClaimType="https://schemas.mydomain.com/identity/advisorId"/>
<Protocol Name="SAML2" PartnerClaimType="https://schemas.mydomain.com/identity/advisorId"/>
</DefaultPartnerClaimTypes>
<UserHelpText>Advisor identifier (ID)</UserHelpText>
</ClaimType>
<ClaimType Id="clientId">
<DisplayName>User's Client Id</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OAuth2" PartnerClaimType="https://schemas.mydomain.com/identity/client/clientId"/>
<Protocol Name="OpenIdConnect" PartnerClaimType="https://schemas.mydomain.com/identity/client/clientId"/>
<Protocol Name="SAML2" PartnerClaimType="https://schemas.mydomain.com/identity/client/clientId"/>
</DefaultPartnerClaimTypes>
<UserHelpText>Client identifier (ID)</UserHelpText>
</ClaimType>
<ClaimType Id="advisorIdAttribute">
<DisplayName>User's Advisor Id</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OAuth2" PartnerClaimType="AdvisorId"/>
</DefaultPartnerClaimTypes>
<UserHelpText>Advisor identifier (ID)</UserHelpText>
</ClaimType>
<ClaimType Id="clientIdAttribute">
<DisplayName>User's Client Id</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OAuth2" PartnerClaimType="ClientId"/>
</DefaultPartnerClaimTypes>
<UserHelpText>Client identifier (ID)</UserHelpText>
</ClaimType>
Then, I have my mapping defined to translate from the claim to the attribute.
<ClaimsTransformation Id="MapAdvisorIdClaimToUserAttribute" TransformationMethod="CopyClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="advisorId" TransformationClaimType="inputClaim" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="advisorIdAttribute" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="MapClientIdClaimToUserAttribute" TransformationMethod="CopyClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="clientId" TransformationClaimType="inputClaim" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="clientIdAttribute" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
Here’s the modified open id configuration
<ClaimsProvider>
<DisplayName>Self Referenced ID Token Hint ClaimsProvider</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="IdTokenHint_ExtractClaims">
<DisplayName>Self referenced ID Token Hint TechnicalProfile</DisplayName>
<Protocol Name="None" />
<Metadata>
<Item Key="METADATA">https://mytenant.b2clogin.com/mytenant.onmicrosoft.com/B2C_1A_INV_redeem/v2.0/.well-known/openid-configuration</Item>
</Metadata>
<OutputClaims>
<!-- claims to read from the id_token_hint-->
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="sub"/>
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name"/>
<OutputClaim ClaimTypeReferenceId="advisorId" PartnerClaimType="https://schemas.mydomain.com/identity/advisorId"/>
<OutputClaim ClaimTypeReferenceId="clientId" PartnerClaimType="https://schemas.mydomain.com/identity/client/clientId"/>
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
And then at the bottom where the comments say to define the claims on the token, I have the following:
<RelyingParty>
<DefaultUserJourney ReferenceId="SignInWithIdTokenHint" />
<UserJourneyBehaviors>
<JourneyInsights TelemetryEngine="ApplicationInsights" InstrumentationKey="111...111" DeveloperMode="true" ClientEnabled="true" ServerEnabled="true" TelemetryVersion="1.0.0" />
<ScriptExecution>Allow</ScriptExecution>
</UserJourneyBehaviors>
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<!--Sample: Set the input claims to be read from the id_token_hint-->
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="displayName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<!--
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="email" />
-->
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="advisorId" PartnerClaimType="https://schemas.mydomain.com/identity/advisorId"/>
<OutputClaim ClaimTypeReferenceId="clientId" PartnerClaimType="https://schemas.mydomain.com/identity/client/clientId"/>
<OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
Here’s where I’m having the issue. I’m trying to get those claims to map so they save to the user attributes. Here’s my modifications.
<ClaimsProvider>
<DisplayName>Local Account</DisplayName>
<TechnicalProfiles>
<!-- Self Asserted page for Signup from an email invite and id_token_hint -->
<TechnicalProfile Id="LocalAccountSignUpFromEmailInvite">
<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>
<Item Key="language.button_continue">Signup</Item>
<Item Key="setting.showCancelButton">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CopyEmailAddress" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="ReadOnlyEmail" />
<InputClaim ClaimTypeReferenceId="displayName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="ReadOnlyEmail" Required="true" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="advisorIdAttribute" />
<OutputClaim ClaimTypeReferenceId="clientIdAttribute" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="MapAdvisorIdClaimToUserAttribute" />
<OutputClaimsTransformation ReferenceId="MapClientIdClaimToUserAttribute" />
</OutputClaimsTransformations>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
<!-- write the user object to the directory -->
<!-- <ValidationTechnicalProfile ReferenceId="SendSignupEvent" /> -->
<!-- notify backend system of user creation -->
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
When I try to upload the policy, I get the following error:
Claim Type “advisorId” is the output claim of the relying party’s technical profile, but it is not an output claim in any of the steps of user journey “SignInWithIdTokenHint”.
I get the same error for client id.
The claims are defined as the output of IdTokenHint_ExtractClaims
as you can see above, and the user journey is unchanged:
<UserJourneys>
<!-- UserJourney to redeem the email invite. It uses id_token_hint to validate the id_token passed -->
<UserJourney Id="SignInWithIdTokenHint">
<OrchestrationSteps>
<!-- Read the input claims from the id_token_hint-->
<OrchestrationStep Order="1" Type="GetClaims" CpimIssuerTechnicalProfileReferenceId="IdTokenHint_ExtractClaims" />
...
What am I missing in order to get this to pass verification, and what am I missing to get the two claims to save into user attributes?