Chris T
Chris T

Reputation: 215

Email missing in Claim - How to find what is passing from B2C and fix?

We have configured to reach B2C via CRM Portal and using custom policies. On Redirect back from signin for a local account to CRM we get the following error

Server Error in '/' Application. Value cannot be null. Parameter name: email

So trying to figure out why email is not being sent as a claim back?

1) How do we find out all the claims being sent back from B2C to CRM?

2) Our SignupOrSignin.xml has the following

  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="displayName" />
    <OutputClaim ClaimTypeReferenceId="givenName" />
    <OutputClaim ClaimTypeReferenceId="surname" />
    <OutputClaim ClaimTypeReferenceId="email" />
    <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
    <OutputClaim ClaimTypeReferenceId="identityProvider" />
    <OutputClaim ClaimTypeReferenceId="trustFrameworkPolicy" Required="true" DefaultValue="{policy}" />
  </OutputClaims>

So we assumed email is being sent back but ofcourse not.

What could be wrong in the userjourney?

<UserJourney Id="SignUpOrSignIn">
  <OrchestrationSteps>

    <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
      <ClaimsProviderSelections>
        <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
      </ClaimsProviderSelections>
      <ClaimsExchanges>
        <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <OrchestrationStep Order="2" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
          <Value>objectId</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
       <ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAUTH" />
        <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- For social IDP authentication, attempt to find the user account in the directory. -->
    <OrchestrationStep Order="3" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
          <Value>authenticationSource</Value>
          <Value>localAccountAuthentication</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId-NoError" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- Show self-asserted page only if the directory does not have the user account already (i.e. we do not have an objectId). 
      This can only happen when authentication happened using a social IDP. If local account was created or authentication done
      using ESTS in step 2, then an user account must exist in the directory by this time. -->
    <OrchestrationStep Order="4" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
          <Value>objectId</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- This step reads any user attributes that we may not have received when authenticating using ESTS so they can be sent 
      in the token. -->
    <OrchestrationStep Order="5" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
          <Value>authenticationSource</Value>
          <Value>socialIdpAuthentication</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
      </ClaimsExchanges>
    </OrchestrationStep>



    <!-- The previous step (SelfAsserted-Social) could have been skipped if there were no attributes to collect 
         from the user. So, in that case, create the user in the directory if one does not already exist 
         (verified using objectId which would be set from the last step if account was created in the directory. -->
    <OrchestrationStep Order="6" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
          <Value>objectId</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <!-- Phone verification: If MFA is not required, the next three steps (#5-#7) should be removed.
         This step checks whether there's a phone number on record,  for the user. If found, then the user is challenged to verify it. -->
    <OrchestrationStep Order="7" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
          <Value>isActiveMFASession</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-InputOrVerify" />
      </ClaimsExchanges>
    </OrchestrationStep>



    <!-- Save MFA phone number: The precondition verifies whether the user provided a new number in the 
         previous step. If so, then the phone number is stored in the directory for future authentication 
         requests. -->
    <OrchestrationStep Order="8" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
          <Value>newPhoneNumberEntered</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneNumberUsingObjectId" />
      </ClaimsExchanges>
    </OrchestrationStep>

    <OrchestrationStep Order="9" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />

  </OrchestrationSteps>
  <ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>

AAD-UserReadUsingObjectId

    <TechnicalProfile Id="AAD-UserReadUsingObjectId">
      <Metadata>
        <Item Key="Operation">Read</Item>
        <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
      </Metadata>
      <IncludeInSso>false</IncludeInSso>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="objectId" Required="true" />
      </InputClaims>     
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
        <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
        <OutputClaim ClaimTypeReferenceId="displayName" />
        <OutputClaim ClaimTypeReferenceId="otherMails" />
        <OutputClaim ClaimTypeReferenceId="givenName" />
        <OutputClaim ClaimTypeReferenceId="surname" />
        <OutputClaim ClaimTypeReferenceId="extension_mustResetPassword" />
      </OutputClaims>
      <IncludeTechnicalProfile ReferenceId="AAD-Common" />
    </TechnicalProfile>

Upvotes: 1

Views: 1189

Answers (1)

Chris Padgett
Chris Padgett

Reputation: 14704

The email claim isn't being issued because it isn't being retrieved by the AAD-UserReadUsingObjectId technical profile.

In the AAD-UserReadUsingObjectId technical profile, you can map from the signInNames.emailAddress claim to the email claim, as follows:

<TechnicalProfile Id="AAD-UserReadUsingObjectId">
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
  </OutputClaims>
</TechnicalProfile>

You can inspect the issued claims by adding an Azure AD B2C application, which replies to either https://jwt.io/ or https://jwt.ms/, and then run the built-in or custom policy for this Azure AD B2C application.

Upvotes: 3

Related Questions