Can Azure-AD B2C use a mobile telephone number as a username?












4















We have a mobile app and website. We would like to use Azure AD-B2C for authentication. We are not going to allow any third party authentication, but instead just use Azure AD in a separate domain.



We would prefer to use the user's telephone number. My research suggests that this feature is requested, but does not exist at this time.



Are there any workarounds for this, or has this feature been implemented and I missed it?










share|improve this question























  • Hi Bryan. You can use anything as the sign-in name for a local account but you might have to use a custom policy for this. Do you want to verify the phone number before it is registered for use?

    – Chris Padgett
    Jan 1 at 23:17











  • Chris, exactly, we want to send a text to the mobile phone number and have the user verify that they are in fact in possession of the phone. Would I use a custom policy for that part?

    – Bryan Schmiedeler
    Jan 2 at 15:41











  • Hi Bryan: Yes, a custom policy is required for that, see below for a sample policy.

    – Chris Padgett
    Jan 4 at 1:20
















4















We have a mobile app and website. We would like to use Azure AD-B2C for authentication. We are not going to allow any third party authentication, but instead just use Azure AD in a separate domain.



We would prefer to use the user's telephone number. My research suggests that this feature is requested, but does not exist at this time.



Are there any workarounds for this, or has this feature been implemented and I missed it?










share|improve this question























  • Hi Bryan. You can use anything as the sign-in name for a local account but you might have to use a custom policy for this. Do you want to verify the phone number before it is registered for use?

    – Chris Padgett
    Jan 1 at 23:17











  • Chris, exactly, we want to send a text to the mobile phone number and have the user verify that they are in fact in possession of the phone. Would I use a custom policy for that part?

    – Bryan Schmiedeler
    Jan 2 at 15:41











  • Hi Bryan: Yes, a custom policy is required for that, see below for a sample policy.

    – Chris Padgett
    Jan 4 at 1:20














4












4








4


1






We have a mobile app and website. We would like to use Azure AD-B2C for authentication. We are not going to allow any third party authentication, but instead just use Azure AD in a separate domain.



We would prefer to use the user's telephone number. My research suggests that this feature is requested, but does not exist at this time.



Are there any workarounds for this, or has this feature been implemented and I missed it?










share|improve this question














We have a mobile app and website. We would like to use Azure AD-B2C for authentication. We are not going to allow any third party authentication, but instead just use Azure AD in a separate domain.



We would prefer to use the user's telephone number. My research suggests that this feature is requested, but does not exist at this time.



Are there any workarounds for this, or has this feature been implemented and I missed it?







azure azure-active-directory azure-ad-b2c






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 31 '18 at 15:02









Bryan SchmiedelerBryan Schmiedeler

1,19421137




1,19421137













  • Hi Bryan. You can use anything as the sign-in name for a local account but you might have to use a custom policy for this. Do you want to verify the phone number before it is registered for use?

    – Chris Padgett
    Jan 1 at 23:17











  • Chris, exactly, we want to send a text to the mobile phone number and have the user verify that they are in fact in possession of the phone. Would I use a custom policy for that part?

    – Bryan Schmiedeler
    Jan 2 at 15:41











  • Hi Bryan: Yes, a custom policy is required for that, see below for a sample policy.

    – Chris Padgett
    Jan 4 at 1:20



















  • Hi Bryan. You can use anything as the sign-in name for a local account but you might have to use a custom policy for this. Do you want to verify the phone number before it is registered for use?

    – Chris Padgett
    Jan 1 at 23:17











  • Chris, exactly, we want to send a text to the mobile phone number and have the user verify that they are in fact in possession of the phone. Would I use a custom policy for that part?

    – Bryan Schmiedeler
    Jan 2 at 15:41











  • Hi Bryan: Yes, a custom policy is required for that, see below for a sample policy.

    – Chris Padgett
    Jan 4 at 1:20

















Hi Bryan. You can use anything as the sign-in name for a local account but you might have to use a custom policy for this. Do you want to verify the phone number before it is registered for use?

– Chris Padgett
Jan 1 at 23:17





Hi Bryan. You can use anything as the sign-in name for a local account but you might have to use a custom policy for this. Do you want to verify the phone number before it is registered for use?

– Chris Padgett
Jan 1 at 23:17













Chris, exactly, we want to send a text to the mobile phone number and have the user verify that they are in fact in possession of the phone. Would I use a custom policy for that part?

– Bryan Schmiedeler
Jan 2 at 15:41





Chris, exactly, we want to send a text to the mobile phone number and have the user verify that they are in fact in possession of the phone. Would I use a custom policy for that part?

– Bryan Schmiedeler
Jan 2 at 15:41













Hi Bryan: Yes, a custom policy is required for that, see below for a sample policy.

– Chris Padgett
Jan 4 at 1:20





Hi Bryan: Yes, a custom policy is required for that, see below for a sample policy.

– Chris Padgett
Jan 4 at 1:20












2 Answers
2






active

oldest

votes


















4














This can be implemented as a custom policy, from the SocialAndLocalAccountsWithMfa starter pack where the end-user's phone number is stored as a sign-in name, with the following changes.



1) Create a custom attribute called PhoneVerified of type Boolean to represent whether the end-user's phone number has been verified.



2) In the TrustFrameworkBase.xml file, add the following claim types to the claims schema:



i. The phone claim type to represent how the end-user's phone number is entered. E.164 is the required format of this claim type:



<ClaimType Id="phone">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
<Restriction>
<Pattern RegularExpression="^+[0-9]{7,15}$" HelpText="Please enter a valid phone number." />
</Restriction>
</ClaimType>


ii. The signInNames.phoneNumber claim type to represent how the end-user's phone number is saved:



<ClaimType Id="signInNames.phoneNumber">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
</ClaimType>


iii. The extension_PhoneVerified claim type to represent whether the end-user's phone number has been verified:



<ClaimType Id="extension_PhoneVerified">
<DisplayName>Phone Number Verified</DisplayName>
<DataType>boolean</DataType>
</ClaimType>


3) In the TrustFrameworkBase.xml file, add the LocalAccountSignUpWithLogonPhone tehcnical profile to the Local Account claims provider and AAD-UserWriteUsingLogonPhone technical profile to the Azure Active Directory claims provider, for registering a new end-user with a phone number:



<TechnicalProfile Id="LocalAccountSignUpWithLogonPhone">
<DisplayName>Phone 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">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="phone" 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" />
<!-- Optional claims, to be collected from the user -->
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonPhone" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


<TechnicalProfile Id="AAD-UserWriteUsingLogonPhone">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="false" AlwaysUseDefaultValue="true" />
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The end-user's phone number is saved as a sign-in name of type phoneNumber and whether the end-user's phone number has been verified is set to false.



4) In the TrustFrameworkBase.xml file, add a SelfAsserted-LocalAccountSignin-Phone technical profile to the Local Account claims provider, for logging in an existing end-user with a phone number:



<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Phone">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonPhoneExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The setting.operatingMode setting is set to Username so that the logon identifier field doesn't have the required format of an email address.



5) In the TrustFrameworkBase.xml file, add a AAD-UserReadForPhoneUsingObjectId technical to the Azure Active Directory claims provider, for getting the end-user's object including the phone profile:



<TechnicalProfile Id="AAD-UserReadForPhoneUsingObjectId">
<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="signInNames.phoneNumber" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneVerified" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>


6) In the TrustFrameworkBase.xml file, add a PhoneFactor-Verify technical profile to the Phone Factor claims provider, for verifying the end-user's phone number:



<TechnicalProfile Id="PhoneFactor-Verify">
<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">false</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="signInNames.phoneNumber" PartnerClaimType="strongAuthenticationPhoneNumber" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="Verified.strongAuthenticationPhoneNumber" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
</TechnicalProfile>


7) In the the TrustFrameworkBase.xml file, add an UserWritePhoneVerifiedUsingObjectId technical profile to the Azure Active Directory claims provider, for setting whether the end-user's phone number has been verified to true:



<TechnicalProfile Id="AAD-UserWritePhoneNumberUsingObjectId">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="true" AlwaysUseDefaultValue="true" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>




Note: Additional technical profiles must be added in the TrustFrameworkBase.xml file to allow an existing end-user to reset their current password using a phone number but this has been left as an exercise for the reader.





8) In the TrustFrameworkBase.xml file, add a SignUpOrSignInForPhone user journey, which allows either a new end-user to register with a phone number or an existing end-user to log in with a phone number and then verifies the end-user's phone number.



<UserJourney Id="SignUpOrSignInForPhone">
<OrchestrationSteps>

<!-- Display the sign-up or sign-in interaction so an existing end-user can sign in with a phone number -->
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninPhoneExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninPhoneExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Phone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- A new end-user has selected to sign up with a phone number -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonPhoneExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonPhone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Read the user object -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadForPhoneUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- If the end-user's phone number hasn't been verified, then verify it during sign-up or following the first sign-in with an unverified phone number -->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-Verify" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Set whether the end-user's phone number has been verified to true -->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneVerifiedUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

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

</OrchestrationSteps>
</UserJourney>


9) Create a relying party file called SignUpOrSignInForPhone.xml (or similar) and reference the SignUpOrSignInForPhone user journey:



<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId="yourtenant.onmicrosoft.com"
PolicyId="B2C_1A_signup_signin_phone"
PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_signup_signin_phone">
<BasePolicy>
<TenantId>yourtenant.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
</BasePolicy>
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInForPhone" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="phone_number" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneNumber" PartnerClaimType="phone_number_verified" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>


The token claims that are output to a relying party include:



i. The phone_number claim that represents the end-user's phone number.



ii. The phone_number_verified claims that represents whether the end-user's phone number has been verified.






share|improve this answer



















  • 1





    Chris, thank you so so much for this. That is awesome!!

    – Bryan Schmiedeler
    Jan 4 at 21:40



















0














I could use a mobile telephone number to sign up as the username for the local in the built-in sign-in or sign-up policy. The process like the following:



enter image description here



And the result is:



enter image description here



Or you could also use the custom policy to make this just like Chris Padgett said.






share|improve this answer


























  • We want to be able to also verify the telephone number by sending out a text to the user and making them take some action, like hit a URL. Can custom policies do that?

    – Bryan Schmiedeler
    Jan 2 at 15:57











  • @BryanSchmiedeler, you could enable MFA in the built-in policy. For the details, you could refer to here.

    – SunnySun
    Jan 3 at 5:32











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53988815%2fcan-azure-ad-b2c-use-a-mobile-telephone-number-as-a-username%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









4














This can be implemented as a custom policy, from the SocialAndLocalAccountsWithMfa starter pack where the end-user's phone number is stored as a sign-in name, with the following changes.



1) Create a custom attribute called PhoneVerified of type Boolean to represent whether the end-user's phone number has been verified.



2) In the TrustFrameworkBase.xml file, add the following claim types to the claims schema:



i. The phone claim type to represent how the end-user's phone number is entered. E.164 is the required format of this claim type:



<ClaimType Id="phone">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
<Restriction>
<Pattern RegularExpression="^+[0-9]{7,15}$" HelpText="Please enter a valid phone number." />
</Restriction>
</ClaimType>


ii. The signInNames.phoneNumber claim type to represent how the end-user's phone number is saved:



<ClaimType Id="signInNames.phoneNumber">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
</ClaimType>


iii. The extension_PhoneVerified claim type to represent whether the end-user's phone number has been verified:



<ClaimType Id="extension_PhoneVerified">
<DisplayName>Phone Number Verified</DisplayName>
<DataType>boolean</DataType>
</ClaimType>


3) In the TrustFrameworkBase.xml file, add the LocalAccountSignUpWithLogonPhone tehcnical profile to the Local Account claims provider and AAD-UserWriteUsingLogonPhone technical profile to the Azure Active Directory claims provider, for registering a new end-user with a phone number:



<TechnicalProfile Id="LocalAccountSignUpWithLogonPhone">
<DisplayName>Phone 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">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="phone" 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" />
<!-- Optional claims, to be collected from the user -->
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonPhone" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


<TechnicalProfile Id="AAD-UserWriteUsingLogonPhone">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="false" AlwaysUseDefaultValue="true" />
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The end-user's phone number is saved as a sign-in name of type phoneNumber and whether the end-user's phone number has been verified is set to false.



4) In the TrustFrameworkBase.xml file, add a SelfAsserted-LocalAccountSignin-Phone technical profile to the Local Account claims provider, for logging in an existing end-user with a phone number:



<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Phone">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonPhoneExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The setting.operatingMode setting is set to Username so that the logon identifier field doesn't have the required format of an email address.



5) In the TrustFrameworkBase.xml file, add a AAD-UserReadForPhoneUsingObjectId technical to the Azure Active Directory claims provider, for getting the end-user's object including the phone profile:



<TechnicalProfile Id="AAD-UserReadForPhoneUsingObjectId">
<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="signInNames.phoneNumber" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneVerified" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>


6) In the TrustFrameworkBase.xml file, add a PhoneFactor-Verify technical profile to the Phone Factor claims provider, for verifying the end-user's phone number:



<TechnicalProfile Id="PhoneFactor-Verify">
<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">false</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="signInNames.phoneNumber" PartnerClaimType="strongAuthenticationPhoneNumber" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="Verified.strongAuthenticationPhoneNumber" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
</TechnicalProfile>


7) In the the TrustFrameworkBase.xml file, add an UserWritePhoneVerifiedUsingObjectId technical profile to the Azure Active Directory claims provider, for setting whether the end-user's phone number has been verified to true:



<TechnicalProfile Id="AAD-UserWritePhoneNumberUsingObjectId">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="true" AlwaysUseDefaultValue="true" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>




Note: Additional technical profiles must be added in the TrustFrameworkBase.xml file to allow an existing end-user to reset their current password using a phone number but this has been left as an exercise for the reader.





8) In the TrustFrameworkBase.xml file, add a SignUpOrSignInForPhone user journey, which allows either a new end-user to register with a phone number or an existing end-user to log in with a phone number and then verifies the end-user's phone number.



<UserJourney Id="SignUpOrSignInForPhone">
<OrchestrationSteps>

<!-- Display the sign-up or sign-in interaction so an existing end-user can sign in with a phone number -->
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninPhoneExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninPhoneExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Phone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- A new end-user has selected to sign up with a phone number -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonPhoneExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonPhone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Read the user object -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadForPhoneUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- If the end-user's phone number hasn't been verified, then verify it during sign-up or following the first sign-in with an unverified phone number -->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-Verify" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Set whether the end-user's phone number has been verified to true -->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneVerifiedUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

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

</OrchestrationSteps>
</UserJourney>


9) Create a relying party file called SignUpOrSignInForPhone.xml (or similar) and reference the SignUpOrSignInForPhone user journey:



<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId="yourtenant.onmicrosoft.com"
PolicyId="B2C_1A_signup_signin_phone"
PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_signup_signin_phone">
<BasePolicy>
<TenantId>yourtenant.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
</BasePolicy>
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInForPhone" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="phone_number" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneNumber" PartnerClaimType="phone_number_verified" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>


The token claims that are output to a relying party include:



i. The phone_number claim that represents the end-user's phone number.



ii. The phone_number_verified claims that represents whether the end-user's phone number has been verified.






share|improve this answer



















  • 1





    Chris, thank you so so much for this. That is awesome!!

    – Bryan Schmiedeler
    Jan 4 at 21:40
















4














This can be implemented as a custom policy, from the SocialAndLocalAccountsWithMfa starter pack where the end-user's phone number is stored as a sign-in name, with the following changes.



1) Create a custom attribute called PhoneVerified of type Boolean to represent whether the end-user's phone number has been verified.



2) In the TrustFrameworkBase.xml file, add the following claim types to the claims schema:



i. The phone claim type to represent how the end-user's phone number is entered. E.164 is the required format of this claim type:



<ClaimType Id="phone">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
<Restriction>
<Pattern RegularExpression="^+[0-9]{7,15}$" HelpText="Please enter a valid phone number." />
</Restriction>
</ClaimType>


ii. The signInNames.phoneNumber claim type to represent how the end-user's phone number is saved:



<ClaimType Id="signInNames.phoneNumber">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
</ClaimType>


iii. The extension_PhoneVerified claim type to represent whether the end-user's phone number has been verified:



<ClaimType Id="extension_PhoneVerified">
<DisplayName>Phone Number Verified</DisplayName>
<DataType>boolean</DataType>
</ClaimType>


3) In the TrustFrameworkBase.xml file, add the LocalAccountSignUpWithLogonPhone tehcnical profile to the Local Account claims provider and AAD-UserWriteUsingLogonPhone technical profile to the Azure Active Directory claims provider, for registering a new end-user with a phone number:



<TechnicalProfile Id="LocalAccountSignUpWithLogonPhone">
<DisplayName>Phone 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">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="phone" 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" />
<!-- Optional claims, to be collected from the user -->
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonPhone" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


<TechnicalProfile Id="AAD-UserWriteUsingLogonPhone">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="false" AlwaysUseDefaultValue="true" />
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The end-user's phone number is saved as a sign-in name of type phoneNumber and whether the end-user's phone number has been verified is set to false.



4) In the TrustFrameworkBase.xml file, add a SelfAsserted-LocalAccountSignin-Phone technical profile to the Local Account claims provider, for logging in an existing end-user with a phone number:



<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Phone">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonPhoneExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The setting.operatingMode setting is set to Username so that the logon identifier field doesn't have the required format of an email address.



5) In the TrustFrameworkBase.xml file, add a AAD-UserReadForPhoneUsingObjectId technical to the Azure Active Directory claims provider, for getting the end-user's object including the phone profile:



<TechnicalProfile Id="AAD-UserReadForPhoneUsingObjectId">
<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="signInNames.phoneNumber" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneVerified" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>


6) In the TrustFrameworkBase.xml file, add a PhoneFactor-Verify technical profile to the Phone Factor claims provider, for verifying the end-user's phone number:



<TechnicalProfile Id="PhoneFactor-Verify">
<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">false</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="signInNames.phoneNumber" PartnerClaimType="strongAuthenticationPhoneNumber" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="Verified.strongAuthenticationPhoneNumber" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
</TechnicalProfile>


7) In the the TrustFrameworkBase.xml file, add an UserWritePhoneVerifiedUsingObjectId technical profile to the Azure Active Directory claims provider, for setting whether the end-user's phone number has been verified to true:



<TechnicalProfile Id="AAD-UserWritePhoneNumberUsingObjectId">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="true" AlwaysUseDefaultValue="true" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>




Note: Additional technical profiles must be added in the TrustFrameworkBase.xml file to allow an existing end-user to reset their current password using a phone number but this has been left as an exercise for the reader.





8) In the TrustFrameworkBase.xml file, add a SignUpOrSignInForPhone user journey, which allows either a new end-user to register with a phone number or an existing end-user to log in with a phone number and then verifies the end-user's phone number.



<UserJourney Id="SignUpOrSignInForPhone">
<OrchestrationSteps>

<!-- Display the sign-up or sign-in interaction so an existing end-user can sign in with a phone number -->
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninPhoneExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninPhoneExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Phone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- A new end-user has selected to sign up with a phone number -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonPhoneExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonPhone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Read the user object -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadForPhoneUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- If the end-user's phone number hasn't been verified, then verify it during sign-up or following the first sign-in with an unverified phone number -->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-Verify" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Set whether the end-user's phone number has been verified to true -->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneVerifiedUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

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

</OrchestrationSteps>
</UserJourney>


9) Create a relying party file called SignUpOrSignInForPhone.xml (or similar) and reference the SignUpOrSignInForPhone user journey:



<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId="yourtenant.onmicrosoft.com"
PolicyId="B2C_1A_signup_signin_phone"
PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_signup_signin_phone">
<BasePolicy>
<TenantId>yourtenant.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
</BasePolicy>
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInForPhone" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="phone_number" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneNumber" PartnerClaimType="phone_number_verified" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>


The token claims that are output to a relying party include:



i. The phone_number claim that represents the end-user's phone number.



ii. The phone_number_verified claims that represents whether the end-user's phone number has been verified.






share|improve this answer



















  • 1





    Chris, thank you so so much for this. That is awesome!!

    – Bryan Schmiedeler
    Jan 4 at 21:40














4












4








4







This can be implemented as a custom policy, from the SocialAndLocalAccountsWithMfa starter pack where the end-user's phone number is stored as a sign-in name, with the following changes.



1) Create a custom attribute called PhoneVerified of type Boolean to represent whether the end-user's phone number has been verified.



2) In the TrustFrameworkBase.xml file, add the following claim types to the claims schema:



i. The phone claim type to represent how the end-user's phone number is entered. E.164 is the required format of this claim type:



<ClaimType Id="phone">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
<Restriction>
<Pattern RegularExpression="^+[0-9]{7,15}$" HelpText="Please enter a valid phone number." />
</Restriction>
</ClaimType>


ii. The signInNames.phoneNumber claim type to represent how the end-user's phone number is saved:



<ClaimType Id="signInNames.phoneNumber">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
</ClaimType>


iii. The extension_PhoneVerified claim type to represent whether the end-user's phone number has been verified:



<ClaimType Id="extension_PhoneVerified">
<DisplayName>Phone Number Verified</DisplayName>
<DataType>boolean</DataType>
</ClaimType>


3) In the TrustFrameworkBase.xml file, add the LocalAccountSignUpWithLogonPhone tehcnical profile to the Local Account claims provider and AAD-UserWriteUsingLogonPhone technical profile to the Azure Active Directory claims provider, for registering a new end-user with a phone number:



<TechnicalProfile Id="LocalAccountSignUpWithLogonPhone">
<DisplayName>Phone 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">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="phone" 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" />
<!-- Optional claims, to be collected from the user -->
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonPhone" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


<TechnicalProfile Id="AAD-UserWriteUsingLogonPhone">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="false" AlwaysUseDefaultValue="true" />
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The end-user's phone number is saved as a sign-in name of type phoneNumber and whether the end-user's phone number has been verified is set to false.



4) In the TrustFrameworkBase.xml file, add a SelfAsserted-LocalAccountSignin-Phone technical profile to the Local Account claims provider, for logging in an existing end-user with a phone number:



<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Phone">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonPhoneExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The setting.operatingMode setting is set to Username so that the logon identifier field doesn't have the required format of an email address.



5) In the TrustFrameworkBase.xml file, add a AAD-UserReadForPhoneUsingObjectId technical to the Azure Active Directory claims provider, for getting the end-user's object including the phone profile:



<TechnicalProfile Id="AAD-UserReadForPhoneUsingObjectId">
<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="signInNames.phoneNumber" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneVerified" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>


6) In the TrustFrameworkBase.xml file, add a PhoneFactor-Verify technical profile to the Phone Factor claims provider, for verifying the end-user's phone number:



<TechnicalProfile Id="PhoneFactor-Verify">
<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">false</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="signInNames.phoneNumber" PartnerClaimType="strongAuthenticationPhoneNumber" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="Verified.strongAuthenticationPhoneNumber" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
</TechnicalProfile>


7) In the the TrustFrameworkBase.xml file, add an UserWritePhoneVerifiedUsingObjectId technical profile to the Azure Active Directory claims provider, for setting whether the end-user's phone number has been verified to true:



<TechnicalProfile Id="AAD-UserWritePhoneNumberUsingObjectId">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="true" AlwaysUseDefaultValue="true" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>




Note: Additional technical profiles must be added in the TrustFrameworkBase.xml file to allow an existing end-user to reset their current password using a phone number but this has been left as an exercise for the reader.





8) In the TrustFrameworkBase.xml file, add a SignUpOrSignInForPhone user journey, which allows either a new end-user to register with a phone number or an existing end-user to log in with a phone number and then verifies the end-user's phone number.



<UserJourney Id="SignUpOrSignInForPhone">
<OrchestrationSteps>

<!-- Display the sign-up or sign-in interaction so an existing end-user can sign in with a phone number -->
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninPhoneExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninPhoneExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Phone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- A new end-user has selected to sign up with a phone number -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonPhoneExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonPhone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Read the user object -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadForPhoneUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- If the end-user's phone number hasn't been verified, then verify it during sign-up or following the first sign-in with an unverified phone number -->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-Verify" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Set whether the end-user's phone number has been verified to true -->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneVerifiedUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

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

</OrchestrationSteps>
</UserJourney>


9) Create a relying party file called SignUpOrSignInForPhone.xml (or similar) and reference the SignUpOrSignInForPhone user journey:



<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId="yourtenant.onmicrosoft.com"
PolicyId="B2C_1A_signup_signin_phone"
PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_signup_signin_phone">
<BasePolicy>
<TenantId>yourtenant.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
</BasePolicy>
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInForPhone" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="phone_number" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneNumber" PartnerClaimType="phone_number_verified" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>


The token claims that are output to a relying party include:



i. The phone_number claim that represents the end-user's phone number.



ii. The phone_number_verified claims that represents whether the end-user's phone number has been verified.






share|improve this answer













This can be implemented as a custom policy, from the SocialAndLocalAccountsWithMfa starter pack where the end-user's phone number is stored as a sign-in name, with the following changes.



1) Create a custom attribute called PhoneVerified of type Boolean to represent whether the end-user's phone number has been verified.



2) In the TrustFrameworkBase.xml file, add the following claim types to the claims schema:



i. The phone claim type to represent how the end-user's phone number is entered. E.164 is the required format of this claim type:



<ClaimType Id="phone">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
<Restriction>
<Pattern RegularExpression="^+[0-9]{7,15}$" HelpText="Please enter a valid phone number." />
</Restriction>
</ClaimType>


ii. The signInNames.phoneNumber claim type to represent how the end-user's phone number is saved:



<ClaimType Id="signInNames.phoneNumber">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
</ClaimType>


iii. The extension_PhoneVerified claim type to represent whether the end-user's phone number has been verified:



<ClaimType Id="extension_PhoneVerified">
<DisplayName>Phone Number Verified</DisplayName>
<DataType>boolean</DataType>
</ClaimType>


3) In the TrustFrameworkBase.xml file, add the LocalAccountSignUpWithLogonPhone tehcnical profile to the Local Account claims provider and AAD-UserWriteUsingLogonPhone technical profile to the Azure Active Directory claims provider, for registering a new end-user with a phone number:



<TechnicalProfile Id="LocalAccountSignUpWithLogonPhone">
<DisplayName>Phone 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">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="phone" 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" />
<!-- Optional claims, to be collected from the user -->
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonPhone" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


<TechnicalProfile Id="AAD-UserWriteUsingLogonPhone">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="false" AlwaysUseDefaultValue="true" />
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The end-user's phone number is saved as a sign-in name of type phoneNumber and whether the end-user's phone number has been verified is set to false.



4) In the TrustFrameworkBase.xml file, add a SelfAsserted-LocalAccountSignin-Phone technical profile to the Local Account claims provider, for logging in an existing end-user with a phone number:



<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Phone">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonPhoneExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>


The setting.operatingMode setting is set to Username so that the logon identifier field doesn't have the required format of an email address.



5) In the TrustFrameworkBase.xml file, add a AAD-UserReadForPhoneUsingObjectId technical to the Azure Active Directory claims provider, for getting the end-user's object including the phone profile:



<TechnicalProfile Id="AAD-UserReadForPhoneUsingObjectId">
<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="signInNames.phoneNumber" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneVerified" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>


6) In the TrustFrameworkBase.xml file, add a PhoneFactor-Verify technical profile to the Phone Factor claims provider, for verifying the end-user's phone number:



<TechnicalProfile Id="PhoneFactor-Verify">
<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">false</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="signInNames.phoneNumber" PartnerClaimType="strongAuthenticationPhoneNumber" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="Verified.strongAuthenticationPhoneNumber" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
</TechnicalProfile>


7) In the the TrustFrameworkBase.xml file, add an UserWritePhoneVerifiedUsingObjectId technical profile to the Azure Active Directory claims provider, for setting whether the end-user's phone number has been verified to true:



<TechnicalProfile Id="AAD-UserWritePhoneNumberUsingObjectId">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="true" AlwaysUseDefaultValue="true" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>




Note: Additional technical profiles must be added in the TrustFrameworkBase.xml file to allow an existing end-user to reset their current password using a phone number but this has been left as an exercise for the reader.





8) In the TrustFrameworkBase.xml file, add a SignUpOrSignInForPhone user journey, which allows either a new end-user to register with a phone number or an existing end-user to log in with a phone number and then verifies the end-user's phone number.



<UserJourney Id="SignUpOrSignInForPhone">
<OrchestrationSteps>

<!-- Display the sign-up or sign-in interaction so an existing end-user can sign in with a phone number -->
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninPhoneExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninPhoneExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Phone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- A new end-user has selected to sign up with a phone number -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonPhoneExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonPhone" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Read the user object -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadForPhoneUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- If the end-user's phone number hasn't been verified, then verify it during sign-up or following the first sign-in with an unverified phone number -->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-Verify" />
</ClaimsExchanges>
</OrchestrationStep>

<!-- Set whether the end-user's phone number has been verified to true -->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneVerifiedUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>

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

</OrchestrationSteps>
</UserJourney>


9) Create a relying party file called SignUpOrSignInForPhone.xml (or similar) and reference the SignUpOrSignInForPhone user journey:



<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId="yourtenant.onmicrosoft.com"
PolicyId="B2C_1A_signup_signin_phone"
PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_signup_signin_phone">
<BasePolicy>
<TenantId>yourtenant.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
</BasePolicy>
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInForPhone" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="phone_number" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneNumber" PartnerClaimType="phone_number_verified" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>


The token claims that are output to a relying party include:



i. The phone_number claim that represents the end-user's phone number.



ii. The phone_number_verified claims that represents whether the end-user's phone number has been verified.







share|improve this answer












share|improve this answer



share|improve this answer










answered Jan 4 at 1:19









Chris PadgettChris Padgett

6,320139




6,320139








  • 1





    Chris, thank you so so much for this. That is awesome!!

    – Bryan Schmiedeler
    Jan 4 at 21:40














  • 1





    Chris, thank you so so much for this. That is awesome!!

    – Bryan Schmiedeler
    Jan 4 at 21:40








1




1





Chris, thank you so so much for this. That is awesome!!

– Bryan Schmiedeler
Jan 4 at 21:40





Chris, thank you so so much for this. That is awesome!!

– Bryan Schmiedeler
Jan 4 at 21:40













0














I could use a mobile telephone number to sign up as the username for the local in the built-in sign-in or sign-up policy. The process like the following:



enter image description here



And the result is:



enter image description here



Or you could also use the custom policy to make this just like Chris Padgett said.






share|improve this answer


























  • We want to be able to also verify the telephone number by sending out a text to the user and making them take some action, like hit a URL. Can custom policies do that?

    – Bryan Schmiedeler
    Jan 2 at 15:57











  • @BryanSchmiedeler, you could enable MFA in the built-in policy. For the details, you could refer to here.

    – SunnySun
    Jan 3 at 5:32
















0














I could use a mobile telephone number to sign up as the username for the local in the built-in sign-in or sign-up policy. The process like the following:



enter image description here



And the result is:



enter image description here



Or you could also use the custom policy to make this just like Chris Padgett said.






share|improve this answer


























  • We want to be able to also verify the telephone number by sending out a text to the user and making them take some action, like hit a URL. Can custom policies do that?

    – Bryan Schmiedeler
    Jan 2 at 15:57











  • @BryanSchmiedeler, you could enable MFA in the built-in policy. For the details, you could refer to here.

    – SunnySun
    Jan 3 at 5:32














0












0








0







I could use a mobile telephone number to sign up as the username for the local in the built-in sign-in or sign-up policy. The process like the following:



enter image description here



And the result is:



enter image description here



Or you could also use the custom policy to make this just like Chris Padgett said.






share|improve this answer















I could use a mobile telephone number to sign up as the username for the local in the built-in sign-in or sign-up policy. The process like the following:



enter image description here



And the result is:



enter image description here



Or you could also use the custom policy to make this just like Chris Padgett said.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 2 at 9:08

























answered Jan 2 at 1:53









SunnySunSunnySun

1,068118




1,068118













  • We want to be able to also verify the telephone number by sending out a text to the user and making them take some action, like hit a URL. Can custom policies do that?

    – Bryan Schmiedeler
    Jan 2 at 15:57











  • @BryanSchmiedeler, you could enable MFA in the built-in policy. For the details, you could refer to here.

    – SunnySun
    Jan 3 at 5:32



















  • We want to be able to also verify the telephone number by sending out a text to the user and making them take some action, like hit a URL. Can custom policies do that?

    – Bryan Schmiedeler
    Jan 2 at 15:57











  • @BryanSchmiedeler, you could enable MFA in the built-in policy. For the details, you could refer to here.

    – SunnySun
    Jan 3 at 5:32

















We want to be able to also verify the telephone number by sending out a text to the user and making them take some action, like hit a URL. Can custom policies do that?

– Bryan Schmiedeler
Jan 2 at 15:57





We want to be able to also verify the telephone number by sending out a text to the user and making them take some action, like hit a URL. Can custom policies do that?

– Bryan Schmiedeler
Jan 2 at 15:57













@BryanSchmiedeler, you could enable MFA in the built-in policy. For the details, you could refer to here.

– SunnySun
Jan 3 at 5:32





@BryanSchmiedeler, you could enable MFA in the built-in policy. For the details, you could refer to here.

– SunnySun
Jan 3 at 5:32


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53988815%2fcan-azure-ad-b2c-use-a-mobile-telephone-number-as-a-username%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Monofisismo

Angular Downloading a file using contenturl with Basic Authentication

Olmecas