Using Conditional Access (CA) with Azure AD B2C custom policies
The Microsoft Learn links are here and here.
The way it works is that CA uses Identity Protection to generate signals based on the type of login and user.
CA then evaluates the signals and passes the required action to B2C, which implements it.
As per the links above, there are some CA templates that you can use:
CA generates three signals:
- Block
- Force MFA
- Force password reset
based on the CA configuration below:
You can also enforce IP address ranges based on named locations.
where you can select the countries you want to ban.
(I just used Albania as a random example!).
The sample custom policy is here.
Before you start, you need to tell CA what “AuthenticationMethodUsed” is set to, based on how the user signs in.
This can be:
- “Password”
- “OneTimePasscode”
You also need to tell CA if the user is registered for MFA based on “IsMfaRegisteredCT” which checks for the presence of one of:
- strongAuthenticationPhoneNumber
- strongAuthenticationEmailAddress
In the policy, you first call CA to evaluate the login risk:
<Candidate SubJourneyReferenceId="ConditionalAccess_Evaluation" />This returns three possible states in a string collection.
Get Rory Braybrook’s stories in your inbox
Join Medium for free to get updates from this writer.
The three states are:
- “mfa”
- “chg_pwd”
- “block”
This collection is then parsed, e.g.:
<TechnicalProfile Id="GenerateCAClaimFlags">
<DisplayName>GenerateCAClaimFlags</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.
ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null"/>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="CAChallengeIsMfa"/>
<OutputClaim ClaimTypeReferenceId="CAChallengeIsChgPwd"/>
<OutputClaim ClaimTypeReferenceId="CAChallengeIsBlock"/>
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="SetCAChallengeIsMfa"/>
<OutputClaimsTransformation ReferenceId="SetCAChallengeIsChgPwd"/>
<OutputClaimsTransformation ReferenceId="SetCAChallengeIsBlock"/>
</OutputClaimsTransformations>
</TechnicalProfile>where e.g. “SetCAChallengeIsMfa” is:
<ClaimsTransformation Id="SetCAChallengeIsMfa" TransformationMethod=
"StringCollectionContains">
<InputClaims>
<InputClaim ClaimTypeReferenceId="conditionalAccessClaimCollection"
TransformationClaimType="inputClaim"/>
</InputClaims>
<InputParameters>
<InputParameter Id="item" DataType="string" Value="mfa"/>
<InputParameter Id="ignoreCase" DataType="string" Value="true"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="CAChallengeIsMfa"
TransformationClaimType="outputClaim"/>
</OutputClaims>
</ClaimsTransformation>If the string collection contains the “mfa” flag, then set CAChallengeIsMfa to True.
Then, e.g. if CAChallengeIsMfa = True, then invoke MFA:
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId=
"PhoneFactor-InputOrVerify"/>
</ClaimsExchanges>“Block” invokes a paragraph type page that halts the flow with a message:
"Due to recent activity associated with your account, your login has been
temporarily blocked." “chg_pwd” invokes a change password flow:
<ClaimsExchanges>
<ClaimsExchange Id="CA_ChangePassword" TechnicalProfileReferenceId=
"LocalAccountWritePasswordUsingObjectId"/>
</ClaimsExchanges>with a message:
"Due to recent activity associated with your account, we require you to change
your password.Then at the end, you tell CA that the risk has been remediated:
<Candidate SubJourneyReferenceId="ConditionalAccess_Remediation" />The results can also be seen in the logs.
I also wrote a post about how to “unit test” this.
All good!










