Customize Adaptive MFA with Rules

The risk assessments in rules will not work unless you enable Adaptive MFA under Security > Multi-factor Auth in the Auth0 Dashboard.

You can use Auth0 Rules to create Adaptive MFA flows for a variety of different scenarios. First, determine the desired behavior:

  • At what confidence level do you want to trigger MFA?

  • How do you want to measure risk? Do you want Auth0 to measure confidence or do you want a custom measurement?

  • How do you want to deal with users who are not enrolled in MFA and go through this flow?

When to use rules for Adaptive MFA

You can use rules to cover a number of different risk assessment scenarios.

Adaptive MFA custom rules are only recommended in scenarios where end users are enrolled in MFA. If a user is not enrolled in MFA and your rule assesses a high risk, you will have very limited options to stop a bad actor. If the end-users are not enrolled in MFA, we recommend using the default policy that ships with adaptive MFA, which will take care of adding extra security for this use case.

Low confidence - high-risk scenarios

User State Desired Login Friction Desired Enrollment Policy Implementation
Enrolled in MFA Require MFA N/A (user already enrolled) Default behavior
Do not require MFA N/A (user already enrolled) Use a rule to bypass MFA
Not enrolled in MFA Require email verification Skip enrollment (do not collect additional authenticators) Default behavior
Require email verification Require MFA enrollment (collect additional authenticator) Use a rule to force MFA enrollment (template available)

High confidence - low-risk scenarios

User State Desired Login Friction Desired Enrollment Policy Implementation
Enrolled in MFA No friction N/A (user already enrolled) Default behavior
Not enrolled in MFA No friction Skip enrollment (do not collect additional authenticators) Default behavior
No friction Require MFA enrollment (collect additional authenticator) Use a rule to force MFA enrollment (template available)

Custom confidence measurement scenarios

If you want to implement your own confidence measure using assessors, use Auth0 rules to build business logic to assess risk, present or bypass MFA challenges, and either require or bypass MFA enrollment (using a collection of additional factors).

Rule action outcomes

If you already use rules to trigger MFA from confidence scores and you enable Adaptive MFA in the Auth0 Dashboard, some actions may be different.

The following table shows the outcomes based on the result of both the rule and the Adaptive MFA action. If your tenant has the confidence score in the rules, then the Adaptive MFA prompt will be triggered when a confidence score is low.

Rule Action Adaptive MFA Action Outcome
Unauthorized Trigger MFA Unauthorized
Unauthorized No MFA Required Unauthorized
Trigger MFA Trigger MFA Trigger MFA
Trigger MFA No MFA Required Trigger MFA
No MFA Required Trigger MFA Trigger MFA
No MFA Required No MFA Required No MFA Required

Rule templates

Auth0 provides two Adaptive MFA rule templates for you to customize: Adaptive MFA and Require MFA Enrollment.

Adaptive MFA rule template

This rule template provides an example and starting point for how to build a custom business rule using individual risk assessments.

First, the rule establishes how the confidence assessments can be read and arranged in a business rule:

  const riskAssessment = context.riskAssessment;

  // Example condition: prompt MFA only based on the NewDevice 
  // confidence level, this will prompt for MFA when a user is logging in 
  // from an unknown device.
  let shouldPromptMfa;
  switch (riskAssessment.assessments.NewDevice.confidence) {
    case 'low':
    case 'medium':
      shouldPromptMfa = true;
      break;
    case 'high':
      shouldPromptMfa = false;
      break;
    case 'neutral':
      // When this assessor has no useful information about the confidence, 
      // do not prompt MFA.
      shouldPromptMfa = false;
      break;
  }

Next, the code checks if the user is enrolled in MFA using user.multifactor; if the user is enrolled in MFA, then trigger the MFA challenge.

  // It only makes sense to prompt for MFA when the user has at least one 
  // enrolled MFA factor.
  const userEnrolledFactors = user.multifactor || [];
  const canPromptMfa = userEnrolledFactors.length > 0;

  if (shouldPromptMfa && canPromptMfa) {
    context.multifactor = {
      provider: 'any',
      // ensure that we will prompt MFA, even if the end-user has selected to 
      // remember the browser.
      allowRememberBrowser: false
    };
  }
  callback(null, user, context);
}

Require MFA Enrollment rule template

This rule template provides a way to enforce MFA enrollment (in an adaptive or standard MFA setting). This rule allows you to address scenarios where, upon risky logins, an end-user is forced to enroll in MFA for security purposes. The rule uses user.multifactor to check if a user is enrolled in MFA and if not, trigger enrollment.

function requireMfaEnrollment(user, context, callback) {

  const enrolledFactors = user.multifactor || [];
  if (enrolledFactors.length === 0) {
    // The user has not enrolled in any MFA factor yet, trigger an MFA enrollment
    context.multifactor = {
      provider: 'any'
    };
  }
  callback(null, user, context);
}

Overwrite Adaptive MFA with Rules

If no action is taken by rules, the outcome defaults to Adaptive MFA. However, in the event you want to use a particular accessor, you can use rules to skip the Adaptive MFA outcome. Apply none to context.multifactor.provider.

} else {
  console.log('SKIP MFA');
  context.multifactor = {
    provider: 'none'
  };
}

Assessors and confidence scores available in rules

Auth0 analyzes how the severity and the interactions between individual assessments predict anomalous behavior, and then assigns an overall risk or confidence score. Low confidence means that the login does not match the patterns previously displayed by the user. The following assessors are computed and available for rules. Confidence assessments are available for use in rules using the context.riskAssessment object. For all assessors, low confidence means that the login does not match patterns previously displayed by a user.

Assessor Description Confidence Score Codes
NewDevice Determines if user is logging in from a known device. low
medium
high
neutral
match
partial_match
no_match
initial_login
unknown_device
no_device_history
assessment_not_available
ImpossibleTravel Determines if the user is logging in from a location signaling impossible travel. low
medium
high
neutral
minimal_travel_from_last_login
travel_from_last_login
substantial_travel_from_last_login
impossible_travel_from_last_login
invalid_travel
mission_geoip
anonymous_proxy
unknown_location
initial_login
location_history_not_found
assessment_not_available
UntrustedIP Shows if the IP was found in Auth0's repository of low reputation IPs. low
medium
high
neutral
not_found_on_deny_list
found_on_deny_list
invalid_ip_address
assessment_not_available
Overall risk score A combination of all 3 assessors shown above. low
medium
high
neutral

In the unlikely case of an assessment back-end system failure, the assessment code will be assessment_not_available and the associated confidence will be low because Auth0 defaults to a secure behavior. You can override this scoring using rules. See Safely handle when Auth0 fails to execute assessors in the use cases below.

The confidence scores are exposed within the riskAssessment context object. Here is the structure of the object accessible in the context of a rule:

context.riskAssessment = {
  confidence: 'low' | 'medium' | 'high' | 'neutral',
  version: '1',
  assessments: {
    UntrustedIP: {
      confidence: 'low' | 'medium' | 'high' | 'neutral',
      code: 'not_found_on_deny_list' | 'found_on_deny_list',
      details: { // only if 'found_on_deny_list'
        ip: '192.168.1.1',
        matches: '192.168.0/64',
        source: 'firehol'
      }
    },
    NewDevice: {
      confidence: 'low' | 'medium' | 'high' | 'neutral',
      code: 'match' | 'partial_match' | 'no_match',
      details: {
        device: 'known' | 'unknown',
        useragent: 'known' | 'unknown',
      }
    },
    ImpossibleTravel: {
      confidence: 'low' | 'medium' | 'high' | 'neutral',
      code: 'missing_geoip', | 'anonymous_proxy' | 'unknown_location' | 'initial_login' | 'location_history_not_found' | 'invalid_travel' | 'minimal_travel_from_last_login' | 'impossible_travel_from_last_login' | 'substantial_travel_from_last_login' | 'travel_from_last_login'
    } 
  }
};

Rule use cases

Here are some suggestions for how to build custom rules based on your use case.

Use Case Implementation
If overall confidence score is X then perform an action. The rule only has to assess the context.riskAssessment.confidence and compare it with constants high, medium, low, or neutral. This use case means that the customer trusts that Auth0’s assessment aggregation approach is sensible. The recommended action is triggering an MFA challenge but it can be customized.
If overall confidence score is below or above X then perform an action. Since the assessor results are surfaced levels, you cannot use comparators such as < or >. We recommend using if (confidence === 'high' or if (confidence !== 'low'.
If overall confidence score is X then get additional details. The riskAssessment object is saved in your tenant logs. View the log entries to see the risk assessment score and the determining factors (reasons). You can view the context.riskAssessment object using a custom rule and report the results elsewhere. For example, you can send an email or save a record in an external database.
If a specific assessor has a specific result then perform an action. Exposing detailed information about assessors allows you to act on a specific risk condition. For example, you might want to block a login transaction if the ImpossibleTravel assessor has the result impossible_travel_from_last_login. You can base your action on the confidence value (low, medium, or high) or on its code. You can also base it on a combination of different assessor results.
Aggregate assessments for a custom overall confidence score. Your rule needs to choose specific assessors and interpret the confidence score (confidence attribute under assessor objects). You may choose to do this if you want a different assessment aggregation approach than Auth0's or if you want to ignore some assessors to get the overall confidence score. With the new score, you can trigger certain actions within the rule.
Based on assessor results, block current transaction with an error and message. You can block the current transaction from completing and raise an UnauthorizedError. You should also redirect the user back to the application (callback) by passing the error and error_message attributes set to relevant values. Raising an UnauthorizedError always sets error=”unauthorized” but the error_message can be customized. For example:
Set a generic error message, no matter what the individual assessor results are (i.e., ”The login attempt was suspicious”).
Set the message to values reflecting the actual assessor results (i.e.. ”The login attempt was suspicious because the client IP address was found in a block list”).
Safely handle when Auth0 fails to execute assessors. Auth0 automatically assigns a low confidence score if there is an assessment failure. If the you want to override this score and perform an action, check to see if the assessor’s code value is set to assessment_not_available in the rule.

Learn more