azure-ad-b2cazure-ad-b2c-custom-policy

QR code URI is correct but QR code not displaying on Azure AD B2C Custom Policy form


Implementing TOTP MFA in Azure AD B2C custom policy.

The QR code URI (qrCodeContent) is being generated correctly and matches the expected format (e.g., otpauth://totp/Test:user@example.com?secret=...&issuer=Test). I have verified and tested this in the claims bag and through logging and using https://zxing.appspot.com/generator.

qrCodeContent

otpauth://totp/Test:steveTest@gmail.com?secret=evrg2znbpbyamdo3&issuer=Test&algorithm=SHA1&digits=6&period=30

Issue

Despite the correct value in qrCodeContent, the QR code is not displaying on the self-asserted form during the user journey.

Troubleshooting steps taken:

ContentDefinition

<ContentDefinition Id="api.selfasserted.totp">
    <LoadUri>~/tenant/templates/AzureBlue/selfasserted.cshtml</LoadUri>
    <RecoveryUri>~/common/default_page_error.html</RecoveryUri>
    <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:1.2.0</DataUri>
    <Metadata>
        <Item Key="DisplayName">TOTP Authenticator Setup</Item>
        <Item Key="IncludeErrorInResponse">true</Item>
    </Metadata>
</ContentDefinition>

Technical Profile

<TechnicalProfile Id="EnableOTPAuthentication">
    <DisplayName>Enable Authenticator app</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.selfasserted.totp</Item>
        <Item Key="language.button_continue">Continue</Item>
    </Metadata>
    <CryptographicKeys>
        <Key Id="issuer_secret"
             StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
    </CryptographicKeys>
    <InputClaimsTransformations>
        <InputClaimsTransformation ReferenceId="CreateSecret" />
        <InputClaimsTransformation ReferenceId="SetTotpIssuer" />
        <InputClaimsTransformation ReferenceId="FormatTotpLabel" />
        <InputClaimsTransformation ReferenceId="CreateQrCodeUri" />
        <!-- same id, new logic -->
    </InputClaimsTransformations>
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="QrCodeScanInstruction"
                    DefaultValue="Scan this QR code with your Authenticator app" />
    </InputClaims>
    <DisplayClaims>
        <DisplayClaim DisplayControlReferenceId="authenticatorAppIconControl" />
        <DisplayClaim ClaimTypeReferenceId="QrCodeScanInstruction" />
        <DisplayClaim DisplayControlReferenceId="totpQrCodeControl" />
        <!-- add this single line -->
        <DisplayClaim DisplayControlReferenceId="authenticatorInfoControl" />
    </DisplayClaims>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" />
        <OutputClaim ClaimTypeReferenceId="secretKey" />
        <!-- add this so the value is sent to the page -->
        <OutputClaim ClaimTypeReferenceId="qrCodeContent" />
    </OutputClaims>
    <UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA-TOTP" />
</TechnicalProfile>

Solution

  • It looks like your page layout version in your ContentDefinition is too old for the page to support TOTP. You've reference v1.2.0 but TOTP wasn't added until v2.1.9 of the self asserted page layout.

    Using the latest page layout version, your ContentDefinition should be:

    <ContentDefinition Id="api.selfasserted.totp">
        <LoadUri>~/tenant/templates/AzureBlue/selfasserted.cshtml</LoadUri>
        <RecoveryUri>~/common/default_page_error.html</RecoveryUri>
        <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.35</DataUri>
        <Metadata>
            <Item Key="DisplayName">TOTP Authenticator Setup</Item>
            <Item Key="IncludeErrorInResponse">true</Item>
        </Metadata>
    </ContentDefinition>