Search code examples
azure-ad-b2cmulti-factor-authenticationaad-b2c

AAD B2C Conditional MFA - Don't Enroll


We use AAD B2C for 30k users and a range of apps. I want to progressively rollout to MFA to a subset of users. Conditional Access Policy sounds perfect, except that as part of the build-in sign-in user flow, users are prompted to enroll in MFA and enter email/phone, even if they are not covered by the Conditional Access policy. This defaults the purpose of slowly rolling out MFA.

This pages suggests Enrollment occurs regardless to Conditional Access. https://learn.microsoft.com/en-us/azure/active-directory-b2c/conditional-access-user-flow?pivots=b2c-user-flow

I've found ways to update the user's authentication phone or email via the Graph API... but I'd rather not do this since I'm not certain I have the correct phone number on hand.

Is there a way to delay the enrollment process?


Solution

  • You could do this with a custom policy.

    Flag the users you’d like to enrol with an extension attribute. Use graph api to do this. In the custom policy read this attribute after the user verified their credentials. Also read the phone number attribute.

    $tenant = "contoso.onmicrosoft.com"
    #B2CUserMigration Application Registration Application Id
    $ClientID      = "" 
    #B2CUserMigration Application Registration generated key (client secret)  
    $ClientSecret  = ""     
    $loginURL = "https://login.microsoftonline.com"
    $resource = "https://graph.microsoft.com"
    
    # Get an OAuth 2 access token based on client id, secret and tenant
    $body = @{grant_type="client_credentials";client_id=$ClientID;client_secret=$ClientSecret;resource=$resource}
    $oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenant/oauth2/token?api-version=1.0 -Body $body
    
    #Part 2 - Register the extension attribute named "requiresMigration" into Azure AD B2C
    #ObjectID of the b2c-extensions-app App Registration
    $AppObjectID = ""
    
    #Set the endpoint to register extension attributes
    $url = "$resource/v1.0/applications/$AppObjectID/extensionProperties"
    
    #Define the extension attribute
    $body = @"
    { 
     "name": "requiresMFA", 
     "dataType": "Boolean", 
     "targetObjects": ["User"]
    }
    "@
    
    #Patch the user
    $objectId = "user objectId to update"
    $url = "$resource/v1.0/users/$objectId"
    
    $body = @"
    {
       extension_GUID-WITHOUT-DASHES_requiresMFA: true
    }
    "@
    

    If the attribute is set to true, and the phone number null, then enrol into mfa. Control the mfa orchestration step with a set of preconditions.

            <TechnicalProfile Id="AAD-UserReadUsingObjectId">
              <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="requiresMFA" DefaultValue="false"/>
                <OutputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" DefaultValue="00"/>
              </OutputClaims>
              <IncludeTechnicalProfile ReferenceId="AAD-Common" />
            </TechnicalProfile>
    
            <OrchestrationStep Order="XX" Type="ClaimsExchange">
              <Preconditions>
                <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                  <Value>isActiveMFASession</Value>
                  <Action>SkipThisOrchestrationStep</Action>
                </Precondition>
                <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                  <Value>requiresMFA</Value>
                  <Value>False</Value>
                  <Action>SkipThisOrchestrationStep</Action>
                </Precondition>
              </Preconditions>
              <ClaimsExchanges>
                <ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-InputOrVerify" />
              </ClaimsExchanges>
            </OrchestrationStep>