> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-fix-docs-5546-update-db-search.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Customize Adaptive MFA

> Learn how to customize Adaptive Multi-Factor Authentication (MFA).

You can customize <Tooltip tip="Adaptive Multi-factor Authentication: Multi-factor authentication (MFA) that is only triggered for users when an attempted login is determined to be a low confidence login." cta="View Glossary" href="/docs/glossary?term=Adaptive+MFA">Adaptive MFA</Tooltip> for a variety of scenarios with [Auth0 Actions](/docs/customize/actions).

## When to customize Adaptive MFA

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  You should only consider customizing Adaptive MFA if your users are enrolled in MFA and are required to use an email as an identifier.
</Callout>

If your users are not enrolled in <Tooltip tip="Multi-factor authentication (MFA): User authentication process that uses a factor in addition to username and password such as a code via SMS." cta="View Glossary" href="/docs/glossary?term=MFA">MFA</Tooltip>, you should use the default policy for Adaptive MFA. If a user is not enrolled in MFA and your Action assesses a high risk, you have limited options to stop a <Tooltip tip="Bad Actors: Entity (a person or group) that poses a threat to the business or environment with the intention to cause harm." cta="View Glossary" href="/docs/glossary?term=bad+actor">bad actor</Tooltip>.

Before you begin to customize Adaptive MFA, ask yourself a few questions:

* 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 will you handle users who are not enrolled in MFA?

## Confidence scores

Adaptive MFA calculates an overall confidence score based on the analysis of three assessments: `NewDevice`, `ImpossibleTravel`, and `UntrustedIP`. To learn more, read [Adaptive MFA: How it works](/docs/secure/multi-factor-authentication/adaptive-mfa).

Each assessment has its own confidence score, and each confidence score has an associated action:

| Confidence score | Description                                                               | Action                        |
| ---------------- | ------------------------------------------------------------------------- | ----------------------------- |
| `low`            | Login transaction does not match patterns previously displayed by user.   | Require MFA.                  |
| `medium`         | Login transaction somewhat matches patterns previously displayed by user. | Do not require MFA.           |
| `high`           | Login transaction closely matches patterns previously displayed by user.  | Do not require MFA.           |
| `neutral`        | N/A. Reserved for future use.                                             | N/A. Reserved for future use. |

<Accordion title="View examples of high- and low-risk scenarios with different confidence scores.">
  The following table describes high-risk scenarios that result in a `low` confidence score:

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

  The following table describes low-risk scenarios that result in a `high` confidence score:

  | User State          | Desired Login Friction | Desired Enrollment Policy                                  | Implementation                                             |
  | ------------------- | ---------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- |
  | Enrolled in MFA     | No friction            | N/A (user already enrolled)                                | Default behavior (no MFA-related Action)                   |
  | Not enrolled in MFA | No friction            | Skip enrollment (do not collect additional authenticators) | Default behavior (no MFA-related Action)                   |
  | Not enrolled in MFA | No friction            | Require MFA enrollment (collect additional authenticator)  | Use an Action to force MFA enrollment (template available) |
</Accordion>

If you want to implement your own method for evaluating the overall confidence score of different scenarios, you can use the data available in the the `riskAssessment` object, which contains the overall confidence score, versioning information, and details of the individual assessments.

You can view the full description, properties, and values of the `riskAssessment` object in the [post-login Actions trigger `riskAssessment` reference](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object#param-risk-assessment).

## Action result outcomes

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Actions that trigger MFA take precedence over default Adaptive MFA behavior.
</Callout>

If any of your Actions trigger MFA based on confidence score, the default Adaptive MFA policy triggers MFA when the confidence score is `low`.

The following table shows the possible outcomes based on the combination of Actions and default Adaptive MFA policy actions.

| Action result   | 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 |

## Action templates

Auth0 provides two Action templates based on Adaptive MFA for you to customize: [Adaptive MFA](#adaptive-mfa-template) and [Require MFA Enrollment](#require-mfa-enrollment-template).

### Adaptive MFA template

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

* The [`api.multifactor.enable`](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-api-object#api-multifactor) Action trigger to handle both enrollment and issue configured MFA challenges at the end of the login flow.
* The [`event.user.multifactor`](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object) Actions trigger with the user's enrolled factors.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Since `email` notifications are not an independent factor, the condition `event.user.multifactor && event.user.multifactor.length > 0` will return `false` if the user only has `email` as a factor. To learn more, read [Configure Email Notifications for MFA](/docs/secure/multi-factor-authentication/multi-factor-authentication-factors/configure-email-notifications-for-mfa).
</Callout>

```javascript lines expandable theme={null}
/**
* Handler that will be called during the execution of a PostLogin flow.
*
* @param {Event} event - Details about the user and the context in which they are logging in.
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
*/
exports.onExecutePostLogin = async (event, api) => {
    // Decide which confidence scores should trigger MFA, for more information refer to
    const promptConfidences = ['low', 'medium'];

    // 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.
    const confidence =
        event.authentication?.riskAssessment?.assessments?.NewDevice
            ?.confidence;
    const shouldPromptMfa =
        confidence && promptConfidences.includes(confidence);

    // It only makes sense to prompt for MFA when the user has at least one
    // enrolled MFA factor.
    const canPromptMfa =
        event.user.multifactor && event.user.multifactor.length > 0;
    if (shouldPromptMfa && canPromptMfa) {
        api.multifactor.enable('any', { allowRememberBrowser: true });
    }
};
```

To prompt users, replace the `api.multifactor.enable` with `api.authentication.challengeWithAny()` to force an MFA challenge with an existing factor the user has already enrolled. To review supported factors with Actions, read about the [`factors` parameter](https://auth0.com/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-api-object#api-authentication-challengewithany-factors). For example:

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  This example uses `event.user.enrolledFactors` instead of `event.user.multifactor` to check enrollment. Unlike `event.user.multifactor`, `event.user.enrolledFactors` includes `email` as a factor, so it correctly returns enrolled factors for users who only have email configured.
</Callout>

```javascript theme={null}
// It only makes sense to prompt for MFA when the user has at least one
// enrolled MFA factor.
const canPromptMfa = event.user.enrolledFactors && event.user.enrolledFactors.length > 0;

if (shouldPromptMfa && canPromptMfa) {
    api.authentication.challengeWithAny([ {type: "email"}, {type:"phone"} ]);
}
```

### Require MFA Enrollment template

This template demonstrates how you could enforce MFA enrollment when using a standard or Adaptive MFA policy. It uses `event.user.multifactor` to check if the user is enrolled in MFA, and if they’re not, prompts for enrollment.

```javascript lines theme={null}
/**
* Handler that will be called during the execution of a PostLogin flow.
*
* @param {Event} event - Details about the user and the context in which they are logging in.
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
*/
exports.onExecutePostLogin = async (event, api) => {
    if (!event.user.multifactor?.length) {
        api.multifactor.enable('any', { allowRememberBrowser: false });
    }
};
```

## Action use cases

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

<AccordionGroup>
  <Accordion title="Perform an action if overall confidence score is X">
    Assess the `riskAssessment.confidence` property, and then compare it with the constants `high`, `medium`, or `low`:

    ```js lines theme={null}
    exports.onExecutePostLogin = async (event, api) => {
      const { riskAssessment } = event.authentication || {};
      const riskIsMedium = riskAssessment && riskAssessment.confidence === 'medium';

      if (riskIsMedium) {
        // ....
      }
    }
    ```
  </Accordion>

  <Accordion title="Perform an action if confidence score is above or below X">
    Confidence scores are discrete values—not in a range—so you cannot use comparison operators (such as `<` or `>`) to evaluate multiple values in a single condition.

    Use multiple conditions to logically combine all the confidence scores you want to handle. For example, if you want to know when the confidence score is greater than `low`, check if it’s equal to `medium` or `high`:

    ```js lines theme={null}
    exports.onExecutePostLogin = async (event, api) => {
      const { riskAssessment } = event.authentication || {};
      const riskIsMediumOrHigh = riskAssessment && 
                                      (riskAssessment.confidence === 'high' || 
                                       riskAssessment.confidence === 'medium');

      if (riskIsMediumOrHigh) {
        // ...
      }
    }
    ```
  </Accordion>

  <Accordion title="Get additional details if overall confidence score is X">
    The `riskAssessment` object is saved in your tenant logs. You can view log entries to see the risk assessment score and the determining factors (reasons).

    You can view the `riskAssessment` object and report the results elsewhere. For example, you can send an email or save a record in an external database.

    ```js lines theme={null}
    exports.onExecutePostLogin = async (event, api) => {
      const { riskAssessment } = event.authentication || {};
      const riskIsLow = riskAssessment && riskAssessment.confidence === 'low';

      if (riskIsLow) {
        // log(externalDatabase, riskAssessment);
      }
    }
    ```
  </Accordion>

  <Accordion title="Perform an action if a specific assessment has a specific result">
    Use the [`assessments` object](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object#param-assessments) to access the details for individual assessments, including the `code` property:

    ```js lines theme={null}
    exports.onExecutePostLogin = async (event, api) => {
      const { riskAssessment } = event.authentication || {};
      const { ImpossibleTravel } = riskAssessment && riskAssessment.assessments;

      if (ImpossibleTravel.code === 'impossible_travel_from_last_login') {
        // ...
      }
    }
    ```
  </Accordion>

  <Accordion title="Aggregate assessments for a custom overall confidence score.">
    Use the [`assessments` object](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object#param-assessments) to access the details for individual assessments, and then use the `confidence` property, the `code` property, or both.
  </Accordion>

  <Accordion title="Block current transaction and return error and message if a specific assessment has a specific result">
    Use the [`assessments` object](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object#param-assessments) to access the details for individual assessments, including the `code` property.

    Block the login transaction from completing by returning the callback function with an `UnauthorizedError` object as the error parameter. The `UnauthorizedError` object always sets `error` to `unauthorized`, but you can customize the `error_message`:

    ```js lines theme={null}
    exports.onExecutePostLogin = async (event, api) => {
      const { riskAssessment } = event.authentication || {};
      const { ImpossibleTravel } = riskAssessment && riskAssessment.assessments;

      if (ImpossibleTravel.code === 'impossible_travel_from_last_login') {
        return api.access.deny('Login blocked due to impossible travel detected.')
      }
    }
    ```

    This redirects the user back to the application's callback URL with the `error` and `error_message` parameters included.
  </Accordion>

  <Accordion title="Safely handle when Auth0 fails to execute assessments">
    Auth0 automatically assigns a `low` confidence score if there is any sort of failure performing the risk assessment.

    To mitigate this scenario, use the [`assessments` object](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object#param-assessments) to inspect the `code` property for each individual assessment and check if the value is set to `assessment_not_available`.
  </Accordion>
</AccordionGroup>

## Learn more

* [Enable Adaptive MFA](/docs/secure/multi-factor-authentication/adaptive-mfa/enable-adaptive-mfa)
* [Adaptive MFA Log Events](/docs/secure/multi-factor-authentication/adaptive-mfa/adaptive-mfa-log-events)
* [Actions Triggers: post-login - API Object](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-api-object)
* [Actions Triggers: post-login - Event Object](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object)
