Azure AD B2C Custom Policy – Multi-Factor Authentication (TOTP- Authentication App)

Introduction:

Multi-factor authentication (MFA) is a security mechanism that requires users to verify their identity using multiple factors before gaining access to an account or system. These factors typically include something the user knows (like a password), something they have (such as a phone or smart card), and something they are (biometrics like fingerprints or facial recognition). MFA significantly enhances security by adding an extra layer of protection against unauthorized access. 

In this article, we are going to see how to enable 2FA with the authentication app TOTP (time-based one-time password) using custom policies in Azure AD B2C

TOTP Display control:

Enable multifactor authentication using Time-Based One-Time Password (TOTP) display controls. End users should use an authenticator app that generates TOTP codes, like Microsoft Authenticator or any other app that supports TOTP verification.

  1. Download the Azure AD B2C Starter pack switch to Display Controls Starterpack -> SocialAndLocalAccountsWithMfa folder and use those display control extension files.
  2. Remove all social account references from the base file, if you are not using any other social account integration.
  3. There are three main display controls to enable TOTP
    • totpQrCodeControl: Display the QR code and a deep link. When the user scans the QR code or clicks the deep link, the authenticator app opens to complete the enrollment process.
    • AuthenticatorAppIconControl: Show the Microsoft Authenticator app icon with a link to download the app to the user’s mobile device.
    • AuthenticatorInfoControl: Provide an introduction to TOTP.

Use the TOTP extension file from Azure AD B2C Custom Policy Sample repo to implement the MFA with TOTP using any authenticator app. Since I use only a local account, removed all social account references from the base file

Pre-populating the email verification control:

This use case is the extension of my last article where I explained how to pre-populate the email address field with the query string data without multi-factor authentication and display control on Sign Up flow. Now we can see how to implement the same use case with the email verification display control.

  1. Created a SignUp user journey in the extension file
<UserJourney Id="SignUpTOTP">
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <!-- Call the TOTP enrollment ub journey. If user already enrolled the sub journey will not ask the user to enroll -->
        <OrchestrationStep Order="3" Type="InvokeSubJourney">
          <JourneyList>
            <Candidate SubJourneyReferenceId="TotpFactor-Input" />
          </JourneyList>
        </OrchestrationStep>

        <!-- Call the TOTP validation sub journey-->
        <OrchestrationStep Order="4" Type="InvokeSubJourney">
          <JourneyList>
            <Candidate SubJourneyReferenceId="TotpFactor-Verify" />
          </JourneyList>
        </OrchestrationStep>

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

      </OrchestrationSteps>
    </UserJourney>

2. Used {OAUTH-KV:email} as a default value for the input value for LocalAccountSignUpWithLogonEmail technical profile to pre-populate the email address field based on the query string value

<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
	<Metadata>
		<Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
	</Metadata>
	<InputClaims>
		<InputClaim ClaimTypeReferenceId="email" DefaultValue="{OAUTH-KV:email}" AlwaysUseDefaultValue="true"   />
	</InputClaims>
  <OutputClaims>
    <!-- The userPrincipalName is required for the AzureMfaProtocolProvider technical profiles-->
    <OutputClaim ClaimTypeReferenceId="userPrincipalName" />
  </OutputClaims>
</TechnicalProfile>

Example: https://gowthamcbe.b2clogin.com/gowthamcbe.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1A_DEMO_SIGNUP_SIGNIN_TOTP&client_id=08294166-1ef2-420c-8826-09d2810041b0&nonce=defaultNonce&redirect_uri=https%3A%2F%2Fjwt.ms&scope=openid&response_type=id_token&prompt=login&email=gowthamkk7@gmail.com

3. Defined the email claim type as read-only

 <ClaimType Id="email">
 	<DisplayName>Email Address</DisplayName>
 	<DataType>string</DataType>
 	<UserInputType>Readonly</UserInputType>
</ClaimType>

4. Created a new signup flow SignUp_TOTP:

<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="gowthamcbe.onmicrosoft.com" 
  PolicyId="B2C_1A_SignUp_TOTP" 
  PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_SignUp_TOTP">

  <BasePolicy>
    <TenantId>gowthamcbe.onmicrosoft.com</TenantId>
    <PolicyId>B2C_1A_Demo_TrustFrameworkExtensions_TOTP</PolicyId>
  </BasePolicy>

  <RelyingParty>
    <DefaultUserJourney ReferenceId="SignUpTOTP" />
    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <OutputClaims>
 
        <OutputClaim ClaimTypeReferenceId="email" />
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
        <OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
      </OutputClaims>
      <SubjectNamingInfo ClaimType="sub" />
    </TechnicalProfile>
  </RelyingParty>
</TrustFrameworkPolicy>

Run the user flow

Sign up user flow


The email address is pre-populated in the email verification display control based on the query string value.

After the email verification and password entry, it will take user to cofigure the Multi factor authentication with Authenticator App

TOTP floq

Next step is to configure the account in Microsoft authentication app for TOTP.

Summary:

We have seen how to configure multi factor authentication with authentication application -TOTP option using custom polices in Azure AD B2C, and we also seen how to read the data from the query string and populate it in Azure AD B2C fields, In this blog we populated the email address field from the query string in the sign up flow.

Check my GitHub repository to get a complete code.

gowthamk91

Leave a Reply

Discover more from Gowtham K

Subscribe now to keep reading and get access to the full archive.

Continue reading