1

I have the need to create Azure B2C user accounts programmatically. In a separate user data store I hold pertinent information about the users I need to set up in B2C including their mobile phone number, which we've already been communicating with them on.

My business requirement is that this mobile phone number is used as a secondary factor during the user's first-time login/password reset experience. I have an initial login experience which uses an externally-created JWT token to take the user to a custom User Journey where they can set a password for the first time.

I understand that it is not yet possible to set the Azure MFA mobile number via Graph API or PowerShell. (Is this still true?). Therefore B2C asks the user to enter their mobile number in the exemplar PhoneFactor-InputOrVerify Technical Profile. This is a security hole as you can just enter any mobile number in there and verify that number.

I can easily programmatically add the user's number to some other field - e.g. the mobile field on the user record.

Question 1. Is there a way to read the user account mobile value and present it to a Technical Profile as if it is the strongAuthenticationPhoneNumber value or Verified.strongAuthenticationPhoneNumber?

Question 2. Is this even a good idea? I imagine there are good reasons not to do this, but I can't fathom what they might be.

I've tried creating new ClaimTypes, reading the 'mobile' field value, creating ClaimsTranfromations to try to make the mobile claim appear to be the strongAuthenticationPhoneNumber claim, and trying generally to 'spoof' B2C into thinking this is the actual number as stored in the MFA data store.

This is the the standard PhoneFactor-InputOrVerify Technical Profile from the starterpack:

<ClaimsProvider>
  <DisplayName>PhoneFactor</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="PhoneFactor-InputOrVerify">
      <DisplayName>PhoneFactor</DisplayName>
      <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.PhoneFactorProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <Metadata>
        <Item Key="ContentDefinitionReferenceId">api.phonefactor</Item>
        <Item Key="ManualPhoneNumberEntryAllowed">true</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
      </CryptographicKeys>
      <InputClaimsTransformations>
        <InputClaimsTransformation ReferenceId="CreateUserIdForMFA" />
      </InputClaimsTransformations>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="userIdForMFA" PartnerClaimType="UserId" />
        <InputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" PartnerClaimType="Verified.OfficePhone" />
        <OutputClaim ClaimTypeReferenceId="newPhoneNumberEntered" PartnerClaimType="newPhoneNumberEntered" />
      </OutputClaims>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
    </TechnicalProfile>

  </TechnicalProfiles>
</ClaimsProvider>

I can provide more code samples of the custom User Journey I mentioned earlier but I don't think this will help with this problem.

Wavy Dave
  • 35
  • 5

1 Answers1

1

You have a few options:

  1. You can add the strongAuthenticationPhoneNumber claim to the same JWT that is used for the onboarding flow and prompt for verification of this phone number during this onboarding flow.
  2. You can map to the strongAuthenticationPhoneNumber claim for the PhoneFactor-InputOrVerify technical profile from the mobile property (or an extension property) of the user object.

For option 1, the onboarding user journey should write the verified phone number to the user object, without the newPhoneNumberEntered-based precondition:

<OrchestrationStep Order="8" Type="ClaimsExchange">
  <ClaimsExchanges>
    <ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneNumberUsingObjectId" />
  </ClaimsExchanges>
</OrchestrationStep>

For option 2, you can map to the strongAuthenticationPhoneNumber claim from the mobile property, as follows:

<InputClaims>
  <InputClaim ClaimTypeReferenceId="userIdForMFA" PartnerClaimType="UserId" />
  <InputClaim ClaimTypeReferenceId="mobile" PartnerClaimType="strongAuthenticationPhoneNumber" />
</InputClaims>
Chris Padgett
  • 14,186
  • 1
  • 15
  • 28
  • Thank you for your help, Chris. You're a shining light of B2C knowledge! I'm having troubles getting this to work, though. I've only had opportunity to try Option 2 so far. It just doesn't seem to be presenting the phone number value as the strongAuthenticationPhoneNumber. Experimenting, I am able to see the 'mobile' value when referenced as an input claim, but presenting is as a PartnerClaimType I see neither a value for 'mobile' nor for 'strongAuthenticationPhoneNumber'. I'll have a go at Option 1 asap, although Option 2 is preferable as we need to perform this task multiple times. – Wavy Dave Jun 21 '19 at 15:13
  • Thank you, @WavyDave, for option 2 did you also add the **mobile** claim as an output claim to the **AAD-UserReadUsingObjectId** technical profile? – Chris Padgett Jun 24 '19 at 06:16
  • Hi Chris, thanks for your reply. I had forgotten to add the mobile output claim to our custom technical profile. This was the issue! – Wavy Dave Jun 24 '19 at 16:16
  • Excellent!, @WavyDave, can you please mark this as answer so that others can refer to it? – Chris Padgett Jun 24 '19 at 22:11