Azure AD B2C Custom Policy - Phone Factor Skip/Bypass Button

Evan Levy 20 Reputation points
2025-01-14T22:10:38.6966667+00:00

Is there a way in an Azure AD B2C custom policy to implement a skip/bypass button on the PhoneFactor-InputOrVerify technical profile utilizing the PhoneFactorProtocolProvider?

On other MFA methods (Software TOTP and email), I have implemented a custom self-service method for resetting MFA for a given user which leads the user to verification orchestration steps before the reset occurs (via REST API call using Graph API). The high-level flow I would like to implement is: (1) user is presented Phone Factor screen with options to send code or call me; (2) user clicks reset MFA link/button; (3) user routed to reset MFA subjourney orchestration steps (i.e., phone factor is bypassed).

The existing functionality I set up for TOTP and email utilizes JavaScript to set a hidden custom claim attribute to true if the user clicks the reset link and then in JavaScript performs a click on the continue button to force a form submit. However, the Phone Factor implementation does not use a form or submit button type similarly. I do see a hidden continue button but this button does not do anything it appears.

I am wondering if there is a way to include a button/link that can force submit/bypass the phone verification to go into a subjourney for performing the reset steps. Any help/suggestions would be greatly appreciated because my only other option I can think of is to move the reset MFA link for all MFA methods before actually getting to the MFA step (which would be a confusing user experience).

Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
23,775 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Evan Levy 20 Reputation points
    2025-01-16T23:24:28.0833333+00:00

    I was able to resolve this on my own. I discovered a way to separate the authentication type selection (send code vs call me options) and verification pieces. To do this, I created a self asserted page for selecting a phone authentication type and based on that output, it either calls the SMS phone factor technical profile or the call phone factor technical profile. Doing this allows me to include a bypass mechanism on the authentication type selection step and move to another subjourney.

    Providing the full sample of my generalized code (note: I have not tested this generalized version).

    First, I created a phoneMfaChoice claim and a self asserted technical profile for the selection of SMS or voice call using the mentioned claim. The skipPhoneFactor claim is a boolean that utilizes JavaScript to mark a hidden checkbox if a link/button is clicked client side.

    <ClaimType Id="phoneMfaChoice">
    	<DisplayName>Phone Authentication Type </DisplayName>
    	<DataType>string</DataType>
    	<UserInputType>RadioSingleSelect</UserInputType>
    	<Restriction>
    		<Enumeration Text="Text Message (SMS)" Value="sms" SelectByDefault="true" />
    		<Enumeration Text="Voice Call" Value="phone" SelectByDefault="false" />
    	</Restriction>
    </ClaimType>
    
    <TechnicalProfile Id="PhoneFactor-Selection">
    	<DisplayName>Allow user to choose an option for phone verification</DisplayName>
    	<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    	<Metadata>
    		<Item Key="ContentDefinitionReferenceId">api.phoneMfaChoice</Item>
    	</Metadata>
    	<InputClaims>
    		<InputClaim ClaimTypeReferenceId="phoneNumber" PartnerClaimType="phoneNumber" />
    	</InputClaims>
    	<OutputClaims>
    		<OutputClaim ClaimTypeReferenceId="phoneNumber" />
    		<OutputClaim ClaimTypeReferenceId="phoneMfaChoice" />
    		<OutputClaim ClaimTypeReferenceId="skipPhoneFactor" DefaultValue="False" />
    	</OutputClaims>
    </TechnicalProfile>
    

    Next, I set up a technical profile for verifying the SMS text message authentication type. This is using the MS Phone Factor technical profile found here: https://learn.microsoft.com/en-us/azure/active-directory-b2c/phone-factor-technical-profile. IMPORTANT: this utilizes the options for setting.authenticationMode "sms" and setting.autodial "true" in order to go from selection page to entering verification code page.

    <TechnicalProfile Id="PhoneFactor-VerifySms">
    	<DisplayName>Phone factor verification via text message (SMS)</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="setting.authenticationMode">sms</Item>
    		<Item Key="setting.autodial">true</Item>
    	</Metadata>
    	<InputClaimsTransformations>
    		<InputClaimsTransformation ReferenceId="CreateUserIdForMFA" />
    	</InputClaimsTransformations>
    	<InputClaims>
    		<InputClaim ClaimTypeReferenceId="userIdForMFA" PartnerClaimType="UserId" />
    		<InputClaim ClaimTypeReferenceId="phoneNumber" />
    	</InputClaims>
    	<OutputClaims>
    		<OutputClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" PartnerClaimType="Verified.OfficePhone" />
    		<OutputClaim ClaimTypeReferenceId="phoneNumber" PartnerClaimType="phoneNumber" />
    	</OutputClaims>
    	<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
    </TechnicalProfile>
    

    Similarly, I set up a technical profile for verifying the phone call authentication type.

    <TechnicalProfile Id="PhoneFactor-VerifyCall">
    	<DisplayName>Phone factor verification via voice call</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="setting.authenticationMode">phone</Item>
    		<Item Key="setting.autodial">true</Item>
    	</Metadata>
    	<InputClaimsTransformations>
    		<InputClaimsTransformation ReferenceId="CreateUserIdForMFA" />
    	</InputClaimsTransformations>
    	<InputClaims>
    		<InputClaim ClaimTypeReferenceId="userIdForMFA" PartnerClaimType="UserId" />
    		<InputClaim ClaimTypeReferenceId="phoneNumber" />
    	</InputClaims>
    	<OutputClaims>
    		<OutputClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" PartnerClaimType="Verified.OfficePhone" />
    		<OutputClaim ClaimTypeReferenceId="phoneNumber" PartnerClaimType="phoneNumber" />
    	</OutputClaims>
    	<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
    </TechnicalProfile>
    

    Below is the full SubJourney for phone verification. The orchestration steps utilize the phoneMfaChoice to pick one or the other for SMS or call. Additionally, there is a precondition to check if skipPhoneFactor is true in order to properly bypass the orchestration steps and move to the next SubJourney.

    <SubJourney Id="PhoneFactor-Verification" Type="Call">
    	<OrchestrationSteps>
    		<OrchestrationStep Order="1" Type="ClaimsExchange">
    			<ClaimsExchanges>
    				<ClaimsExchange Id="PhoneFactorSelection" TechnicalProfileReferenceId="PhoneFactor-Selection" />
    			</ClaimsExchanges>
    		</OrchestrationStep>
    		<OrchestrationStep Order="2" Type="ClaimsExchange">
    			<Preconditions>
    				<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
    					<Value>phoneMfaChoice</Value>
    					<Value>sms</Value>
    					<Action>SkipThisOrchestrationStep</Action>
    				</Precondition>
    				<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
    					<Value>skipPhoneFactor</Value>
    					<Value>True</Value>
    					<Action>SkipThisOrchestrationStep</Action>
    				</Precondition>
    			</Preconditions>
    			<ClaimsExchanges>
    				<ClaimsExchange Id="PhoneFactorVerifySms" TechnicalProfileReferenceId="PhoneFactor-VerifySms" />
    			</ClaimsExchanges>
    		</OrchestrationStep>
    		<OrchestrationStep Order="3" Type="ClaimsExchange">
    			<Preconditions>
    				<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
    					<Value>phoneMfaChoice</Value>
    					<Value>phone</Value>
    					<Action>SkipThisOrchestrationStep</Action>
    				</Precondition>
    				<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
    					<Value>skipPhoneFactor</Value>
    					<Value>True</Value>
    					<Action>SkipThisOrchestrationStep</Action>
    				</Precondition>
    			</Preconditions>
    			<ClaimsExchanges>
    				<ClaimsExchange Id="PhoneFactorVerifyCall" TechnicalProfileReferenceId="PhoneFactor-VerifyCall" />
    			</ClaimsExchanges>
    		</OrchestrationStep>
    	</OrchestrationSteps>
    </SubJourney>
    
    
    0 comments No comments

  2. Raja Pothuraju 17,485 Reputation points Microsoft External Staff
    2025-01-17T02:15:58.11+00:00

    Hello @Evan Levy,

    Thank you for sharing your Answer here.

    I am reposting your answer as my answer to help other community members who have similar issues.

    I discovered a way to separate the authentication type selection (send code vs call me options) and verification pieces. To do this, I created a self-asserted page for selecting a phone authentication type and based on that output, it either calls the SMS phone factor technical profile or the call phone factor technical profile. Doing this allows me to include a bypass mechanism on the authentication type selection step and move to another subjourney.

    Providing the full sample of my generalized code (note: I have not tested this generalized version).

    First, I created a phoneMfaChoice claim and a self asserted technical profile for the selection of SMS or voice call using the mentioned claim. The skipPhoneFactor claim is a boolean that utilizes JavaScript to mark a hidden checkbox if a link/button is clicked client side.

    <ClaimType Id="phoneMfaChoice">
    	<DisplayName>Phone Authentication Type </DisplayName>
    	<DataType>string</DataType>
    	<UserInputType>RadioSingleSelect</UserInputType>
    	<Restriction>
    		<Enumeration Text="Text Message (SMS)" Value="sms" SelectByDefault="true" />
    		<Enumeration Text="Voice Call" Value="phone" SelectByDefault="false" />
    	</Restriction>
    </ClaimType>
    
    <TechnicalProfile Id="PhoneFactor-Selection">
    	<DisplayName>Allow user to choose an option for phone verification</DisplayName>
    	<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    	<Metadata>
    		<Item Key="ContentDefinitionReferenceId">api.phoneMfaChoice</Item>
    	</Metadata>
    	<InputClaims>
    		<InputClaim ClaimTypeReferenceId="phoneNumber" PartnerClaimType="phoneNumber" />
    	</InputClaims>
    	<OutputClaims>
    		<OutputClaim ClaimTypeReferenceId="phoneNumber" />
    		<OutputClaim ClaimTypeReferenceId="phoneMfaChoice" />
    		<OutputClaim ClaimTypeReferenceId="skipPhoneFactor" DefaultValue="False" />
    	</OutputClaims>
    </TechnicalProfile>
    

    Next, I set up a technical profile for verifying the SMS text message authentication type. This is using the MS Phone Factor technical profile found here: https://learn.microsoft.com/en-us/azure/active-directory-b2c/phone-factor-technical-profile. IMPORTANT: this utilizes the options for setting.authenticationMode "sms" and setting.autodial "true" in order to go from selection page to entering verification code page.

    <TechnicalProfile Id="PhoneFactor-VerifySms">
    	<DisplayName>Phone factor verification via text message (SMS)</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="setting.authenticationMode">sms</Item>
    		<Item Key="setting.autodial">true</Item>
    	</Metadata>
    	<InputClaimsTransformations>
    		<InputClaimsTransformation ReferenceId="CreateUserIdForMFA" />
    	</InputClaimsTransformations>
    	<InputClaims>
    		<InputClaim ClaimTypeReferenceId="userIdForMFA" PartnerClaimType="UserId" />
    		<InputClaim ClaimTypeReferenceId="phoneNumber" />
    	</InputClaims>
    	<OutputClaims>
    		<OutputClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" PartnerClaimType="Verified.OfficePhone" />
    		<OutputClaim ClaimTypeReferenceId="phoneNumber" PartnerClaimType="phoneNumber" />
    	</OutputClaims>
    	<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
    </TechnicalProfile>
    

    Similarly, I set up a technical profile for verifying the phone call authentication type.

    <TechnicalProfile Id="PhoneFactor-VerifyCall">
    	<DisplayName>Phone factor verification via voice call</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="setting.authenticationMode">phone</Item>
    		<Item Key="setting.autodial">true</Item>
    	</Metadata>
    	<InputClaimsTransformations>
    		<InputClaimsTransformation ReferenceId="CreateUserIdForMFA" />
    	</InputClaimsTransformations>
    	<InputClaims>
    		<InputClaim ClaimTypeReferenceId="userIdForMFA" PartnerClaimType="UserId" />
    		<InputClaim ClaimTypeReferenceId="phoneNumber" />
    	</InputClaims>
    	<OutputClaims>
    		<OutputClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" PartnerClaimType="Verified.OfficePhone" />
    		<OutputClaim ClaimTypeReferenceId="phoneNumber" PartnerClaimType="phoneNumber" />
    	</OutputClaims>
    	<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
    </TechnicalProfile>
    

    Below is the full SubJourney for phone verification. The orchestration steps utilize the phoneMfaChoice to pick one or the other for SMS or call. Additionally, there is a precondition to check if skipPhoneFactor is true in order to properly bypass the orchestration steps and move to the next SubJourney.

    <SubJourney Id="PhoneFactor-Verification" Type="Call">
    	<OrchestrationSteps>
    		<OrchestrationStep Order="1" Type="ClaimsExchange">
    			<ClaimsExchanges>
    				<ClaimsExchange Id="PhoneFactorSelection" TechnicalProfileReferenceId="PhoneFactor-Selection" />
    			</ClaimsExchanges>
    		</OrchestrationStep>
    		<OrchestrationStep Order="2" Type="ClaimsExchange">
    			<Preconditions>
    				<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
    					<Value>phoneMfaChoice</Value>
    					<Value>sms</Value>
    					<Action>SkipThisOrchestrationStep</Action>
    				</Precondition>
    				<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
    					<Value>skipPhoneFactor</Value>
    					<Value>True</Value>
    					<Action>SkipThisOrchestrationStep</Action>
    				</Precondition>
    			</Preconditions>
    			<ClaimsExchanges>
    				<ClaimsExchange Id="PhoneFactorVerifySms" TechnicalProfileReferenceId="PhoneFactor-VerifySms" />
    			</ClaimsExchanges>
    		</OrchestrationStep>
    		<OrchestrationStep Order="3" Type="ClaimsExchange">
    			<Preconditions>
    				<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
    					<Value>phoneMfaChoice</Value>
    					<Value>phone</Value>
    					<Action>SkipThisOrchestrationStep</Action>
    				</Precondition>
    				<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
    					<Value>skipPhoneFactor</Value>
    					<Value>True</Value>
    					<Action>SkipThisOrchestrationStep</Action>
    				</Precondition>
    			</Preconditions>
    			<ClaimsExchanges>
    				<ClaimsExchange Id="PhoneFactorVerifyCall" TechnicalProfileReferenceId="PhoneFactor-VerifyCall" />
    			</ClaimsExchanges>
    		</OrchestrationStep>
    	</OrchestrationSteps>
    </SubJourney>
    

    Thanks.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.