> ## Documentation Index
> Fetch the complete documentation index at: https://docs-staging-quickstart-revamp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

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

# Customize Adaptive 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?

## Evaluate confidence

Adaptive MFA calculates an overall confidence score based on the analysis of three assessments. Each assessment has its own confidence score. To learn more, read [Adaptive MFA](/docs/secure/multi-factor-authentication/adaptive-mfa).

### Confidence scores

Confidence scores and their associated actions are described below:

<table class="table">
  <thead>
    <tr>
      <th><strong>Confidence score</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Action</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>low</code></td>
      <td>Login transaction does not match patterns previously displayed by user.</td>
      <td>Require MFA.</td>
    </tr>

    <tr>
      <td><code>medium</code></td>
      <td>Login transaction somewhat matches patterns previously displayed by user.</td>
      <td>Do not require MFA.</td>
    </tr>

    <tr>
      <td><code>high</code></td>
      <td>Login transaction closely matches patterns previously displayed by user.</td>
      <td>Do not require MFA.</td>
    </tr>

    <tr>
      <td><code>neutral</code></td>
      <td>N/A. Reserved for future use.</td>
      <td>N/A. Reserved for future use.</td>
    </tr>
  </tbody>
</table>

### Custom confidence scoring

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 [riskAssessment](#riskassessment-context-object) object.

Read the examples below to learn how Adaptive MFA would score the confidence of different use cases.

#### Examples of high-risk, low-confidence scenarios

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

<table class="table">
  <thead>
    <tr>
      <th><strong>User State</strong></th>
      <th><strong>Desired Login Friction</strong></th>
      <th><strong>Desired Enrollment Policy</strong></th>
      <th><strong>Implementation</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>Enrolled in MFA</td>
      <td>Do not require MFA</td>
      <td>N/A (user already enrolled)</td>
      <td>Use an Action to bypass MFA</td>
    </tr>

    <tr>
      <td>Not enrolled in MFA</td>
      <td>Require email verification</td>
      <td>Skip enrollment (do not collect additional authenticators)</td>
      <td>Default behavior (no MFA-related Action)</td>
    </tr>

    <tr>
      <td>Not enrolled in MFA</td>
      <td>Require email verification</td>
      <td>Require MFA enrollment (collect additional authenticator)</td>
      <td>Use an Action to force MFA enrollment (template available)</td>
    </tr>
  </tbody>
</table>

#### Examples of low-risk, high-confidence scenarios

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

<table class="table">
  <thead>
    <tr>
      <th><strong>User State</strong></th>
      <th><strong>Desired Login Friction</strong></th>
      <th><strong>Desired Enrollment Policy</strong></th>
      <th><strong>Implementation</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>Enrolled in MFA</td>
      <td>No friction</td>
      <td>N/A (user already enrolled)</td>
      <td>Default behavior (no MFA-related Action)</td>
    </tr>

    <tr>
      <td>Not enrolled in MFA</td>
      <td>No friction</td>
      <td>Skip enrollment (do not collect additional authenticators)</td>
      <td>Default behavior (no MFA-related Action)</td>
    </tr>

    <tr>
      <td>Not enrolled in MFA</td>
      <td>No friction</td>
      <td>Require MFA enrollment (collect additional authenticator)</td>
      <td>Use an Action to force MFA enrollment (template available)</td>
    </tr>
  </tbody>
</table>

### riskAssessment object

The `riskAssessment` object contains the overall confidence score, versioning information, and details of the individual assessments.

<table class="table">
  <thead>
    <tr>
      <th><strong>Property</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Type</strong></th>
      <th><strong>Possible values</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>confidence</code></td>
      <td>Overall confidence score calculated by Adaptive MFA.</td>
      <td>string</td>
      <td><code>low</code>, <code>medium</code>, <code>high</code>, <code>neutral</code></td>
    </tr>

    <tr>
      <td><code>version</code></td>
      <td>Version identifier of risk assessment API.</td>
      <td>string</td>
      <td><code>1</code></td>
    </tr>

    <tr>
      <td><code>assessments</code></td>
      <td>Object containing individual assessment details.</td>
      <td>object</td>
      <td>Read <a href="#assessments-object">assessments object</a></td>
    </tr>
  </tbody>
</table>

```js lines expandable
exports.onExecutePostLogin = async (event, api) => {
  if (event.authentication && event.authentication.riskAssessment) {
    event.authentication.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',
            category: 'abuse'
          }
        },
        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'
        } 
      },
       PhoneNumber: {
          code: "requires_verification | ok",
          confidence: "low | medium | high | neutral",
          details: {
	        	lineType: "FIXED_LINE | MOBILE | FIXED_LINE_OR_MOBILE | TOLL_FREE | PREMIUM_RATE | SHARED_COST | VOIP | PERSONAL_NUMBER | PAGER | UAN | UNKNOWN"
	            isValid: true | false,
		        countryCode: 1,
		        number: "+12223334444"
        }
      }
    };
  }
}
```

### assessments object

The `assessments` object contains details of the three individual risk assessments:

1. [NewDevice assessment](#newdevice-assessment)
2. [ImpossibleTravel assessment](#impossibletravel-assessment)
3. [UntrustedIP assessment](#untrustedip-assessment)
4. [PhoneNumber assessment](#phonenumber-assessment)

Each assessment includes a [confidence score](#confidence-scores), a code that describes the evaluation result, and additional contextual information.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  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 Actions. To learn more, read [Safely handle when Auth0 fails to execute assessors](#safely-handle-when-auth0-fails-execute-assessors).
</Callout>

#### NewDevice assessment

The `NewDevice` assessment determines if the user is logging in from a known device and contains the following properties:

<table class="table">
  <thead>
    <tr>
      <th><strong>Property</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Type</strong></th>
      <th><strong>Possible values</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>confidence</code></td>
      <td>Confidence score calculated by Adaptive MFA.</td>
      <td>string</td>
      <td><code>low</code>, <code>medium</code>, <code>high</code>, <code>neutral</code></td>
    </tr>

    <tr>
      <td><code>code</code></td>
      <td>Evaluation result of the assessment.</td>
      <td>string</td>
      <td><code>match</code>, <code>partial\_match</code>, <code>no\_match</code>, <code>initial\_login</code>, <code>unknown\_device</code>, <code>no\_device\_history</code>, <code>assessment\_not\_available</code></td>
    </tr>

    <tr>
      <td><code>details</code></td>
      <td>Additional contextual information.</td>
      <td>object</td>
      <td>Refer to table below.</td>
    </tr>
  </tbody>
</table>

##### NewDevice assessment code property

The `NewDevice` assessment `code` property equals one of the following values:

<table class="table">
  <thead>
    <tr>
      <th><strong>Value</strong></th>
      <th><strong>Description</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>match</code></td>
      <td>The property values of the <code>details</code> object are equivalent.</td>
    </tr>

    <tr>
      <td><code>partial\_match</code></td>
      <td>The property values of the <code>details</code> object are similar.</td>
    </tr>

    <tr>
      <td><code>no\_match</code></td>
      <td>The property values of the <code>details</code> object are different.</td>
    </tr>

    <tr>
      <td><code>initial\_login</code></td>
      <td>The user logged in for the first time on the device.</td>
    </tr>

    <tr>
      <td><code>unknown\_device</code></td>
      <td>Auth0 was unable to attain metadata for the device.</td>
    </tr>

    <tr>
      <td><code>no\_device\_history</code></td>
      <td>There is no login history associated with the device.</td>
    </tr>

    <tr>
      <td><code>assessment\_not\_available</code></td>
      <td>Auth0 could not perform an assessment of the device.</td>
    </tr>
  </tbody>
</table>

##### NewDevice assessment details object

If the `code` property value equals `match`, `partial_match`, or `no_match`, the `NewDevice` assessment contains the `details` object with the following properties:

<table class="table">
  <thead>
    <tr>
      <th><strong>Property</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Type</strong></th>
      <th><strong>Possible values</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>device</code></td>
      <td>Device of the user.</td>
      <td>string</td>
      <td><code>known</code>, <code>unknown</code></td>
    </tr>

    <tr>
      <td><code>useragent</code></td>
      <td>User agent of the user.</td>
      <td>string</td>
      <td><code>known</code>, <code>unknown</code></td>
    </tr>
  </tbody>
</table>

#### ImpossibleTravel assessment

The `ImpossibleTravel` assessment determines if the user is logging in from a location that would indicate impossible travel and contains the following properties:

<table class="table">
  <thead>
    <tr>
      <th><strong>Property</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Type</strong></th>
      <th><strong>Possible values</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>confidence</code></td>
      <td>Confidence score calculated by Adaptive MFA.</td>
      <td>string</td>
      <td><code>low</code>, <code>medium</code>, <code>high</code>, <code>neutral</code></td>
    </tr>

    <tr>
      <td><code>code</code></td>
      <td>Evaluation result of the assessment.</td>
      <td>string</td>
      <td><code>minimal\_travel\_from\_last\_login</code>, <code>travel\_from\_last\_login</code>, <code>substantial\_travel\_from\_last\_login</code>, <code>impossible\_travel\_from\_last\_login</code>, <code>invalid\_travel</code>, <code>missing\_geoip</code>, <code>anonymous\_proxy</code>, <code>unknown\_location</code>, <code>initial\_login</code>, <code>location\_history\_not\_found</code>, <code>assessment\_not\_available</code></td>
    </tr>
  </tbody>
</table>

#### UntrustedIP assessment

The `UntrustedIP` assessment determines if the user’s IP address is present in Auth0’s repository of low-reputation IP addresses (“deny list”) and contains the following properties:

<table class="table">
  <thead>
    <tr>
      <th><strong>Property</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Type</strong></th>
      <th><strong>Possible values</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>confidence</code></td>
      <td>Confidence score calculated by Adaptive MFA.</td>
      <td>string</td>
      <td><code>low</code>, <code>medium</code>, <code>high</code>, <code>neutral</code></td>
    </tr>

    <tr>
      <td><code>code</code></td>
      <td>Evaluation result of the assessment.</td>
      <td>string</td>
      <td><code>not\_found\_on\_deny\_list</code>, <code>found\_on\_deny\_list</code>, <code>invalid\_ip\_address</code>, <code>assessment\_not\_available</code></td>
    </tr>

    <tr>
      <td><code>details</code></td>
      <td>Additional contextual information.</td>
      <td>object</td>
      <td>Refer to table below.</td>
    </tr>
  </tbody>
</table>

##### UntrustedIP assessment details object

If the `UntrustedIP` assessment `code` property value equals `found_on_deny_list`, the `details` object is present and contains the following properties:

<table class="table">
  <thead>
    <tr>
      <th><strong>Property</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Type</strong></th>
      <th><strong>Possible values</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>ip</code></td>
      <td>IP address of the device.</td>
      <td>string</td>
      <td>Any valid IPv4 or IPv6 address.</td>
    </tr>

    <tr>
      <td><code>matches</code></td>
      <td>Subnet mask that IP address belongs to.</td>
      <td>string</td>
      <td>Any valid IPv4 or IPv6 subnet mask.</td>
    </tr>

    <tr>
      <td><code>source</code></td>
      <td>Name of threat intelligence source for the deny list.</td>
      <td>string</td>
      <td>Any valid text.</td>
    </tr>

    <tr>
      <td><code>category</code></td>
      <td>Category indicating why IP address is untrusted.</td>
      <td>string</td>
      <td><code>abuse</code>, <code>anonymizer</code>, <code>datacenter</code>, <code>reputation</code>, <code>unroutable</code></td>
    </tr>
  </tbody>
</table>

##### UntrustedIP assessment details object category property

The `UntrustedIP` assessment `details` object `category` property describes the general reason why Adaptive MFA considers a given IP address untrusted and equals one of the following values:

<table class="table">
  <thead>
    <tr>
      <th><strong>Value</strong></th>
      <th><strong>Description</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>abuse</code></td>
      <td>IP address exhibited abusive behaviors or was found to be member of bot nets.</td>
    </tr>

    <tr>
      <td><code>anonymizer</code></td>
      <td>IP address belongs to anonymizing services such as VPN providers, open proxies, and TOR exit nodes.</td>
    </tr>

    <tr>
      <td><code>datacenter</code></td>
      <td>IP address belongs to cloud hosting providers and colocation datacenters.</td>
    </tr>

    <tr>
      <td><code>reputation</code></td>
      <td>IP address has a poor reputation score based on activity.</td>
    </tr>

    <tr>
      <td><code>unroutable</code></td>
      <td>IP address is not in any range allocated or delegated by any authorized Internet registry or allowed for public use.</td>
    </tr>
  </tbody>
</table>

#### PhoneNumber assessment

The `PhoneNumber` assessment assesses the risk of a phone number for an incoming transaction and contains the following properties:

<table class="table">
  <thead>
    <tr>
      <th><strong>Property</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Type</strong></th>
      <th><strong>Possible values</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>code</code></td>
      <td>Describes the evaluation result.</td>
      <td>string</td>
      <td><code>ok</code>, <code>requires\_verification</code>, <code>phone\_number\_not\_provided</code>, <code>assessment\_not\_available</code></td>
    </tr>

    <tr>
      <td><code>confidence</code></td>
      <td>Confidence score calculated by Adaptive MFA.</td>
      <td>string</td>
      <td><code>low</code>, <code>medium</code>, <code>high</code>, <code>neutral</code></td>
    </tr>

    <tr>
      <td><code>details</code></td>
      <td>Additional contextual information.</td>
      <td>object</td>
      <td>Refer to table below.</td>
    </tr>
  </tbody>
</table>

##### PhoneNumber assessment details object

The `PhoneNumber` assessment `details` object contains the following properties:

<table class="table">
  <thead>
    <tr>
      <th><strong>Property</strong></th>
      <th><strong>Description</strong></th>
      <th><strong>Type</strong></th>
      <th><strong>Possible values</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>lineType</code></td>
      <td>Type of phone line</td>
      <td>string</td>
      <td><code>FIXED\_LINE</code>, <code>MOBILE</code>, <code>FIXED\_LINE\_OR\_MOBILE</code>, <code>TOLL\_FREE</code>, <code>PREMIUM\_RATE</code>, <code>SHARED\_COST</code>, <code>VOIP</code>, <code>PERSONAL\_NUMBER</code>, <code>PAGER</code>, <code>UAN</code>, <code>UNKNOWN</code></td>
    </tr>

    <tr>
      <td><code>isValid</code></td>
      <td>Returns the validity of the number</td>
      <td>boolean</td>
      <td><code>true</code>, <code>false</code></td>
    </tr>

    <tr>
      <td><code>countryCode</code></td>
      <td>Country code of the phone origin</td>
      <td>integer</td>
      <td><code>0-999</code></td>
    </tr>

    <tr>
      <td><code>number</code></td>
      <td>Phone number</td>
      <td>string</td>
      <td>Valid number including <code>countryCode</code></td>
    </tr>
  </tbody>
</table>

## 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.

<table class="table">
  <thead>
    <tr>
      <th><strong>Action result</strong></th>
      <th><strong>Adaptive MFA action</strong></th>
      <th><strong>Outcome</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>Unauthorized</td>
      <td>Trigger MFA</td>
      <td>Unauthorized</td>
    </tr>

    <tr>
      <td>Unauthorized</td>
      <td>No MFA Required</td>
      <td>Unauthorized</td>
    </tr>

    <tr>
      <td>Trigger MFA</td>
      <td>Trigger MFA</td>
      <td>Trigger MFA</td>
    </tr>

    <tr>
      <td>Trigger MFA</td>
      <td>No MFA Required</td>
      <td>Trigger MFA</td>
    </tr>

    <tr>
      <td>No MFA Required</td>
      <td>Trigger MFA</td>
      <td>Trigger MFA</td>
    </tr>

    <tr>
      <td>No MFA Required</td>
      <td>No MFA Required</td>
      <td>No MFA Required</td>
    </tr>
  </tbody>
</table>

## Action templates

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

### Adaptive MFA template

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

```javascript lines expandable
/**
* 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.authentication && 
      event.authentication.riskAssessment && 
      event.authentication.riskAssessment.assessments.NewDevice) {

  // 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 (event.authentication.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;
    }

      // 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 });
    }
  }
};
```

### 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
/**
* 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 || event.user.multifactor.length == 0) {
    api.multifactor.enable('any', { allowRememberBrowser: true });
  }
};
```

## Action use cases

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

### 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
exports.onExecutePostLogin = async (event, api) => {
  const { riskAssessment } = event.authentication || {};
  const riskIsMedium = riskAssessment && riskAssessment.confidence === 'medium';

  if (riskIsMedium) {
    // ....
  }
}
```

### 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
exports.onExecutePostLogin = async (event, api) => {
  const { riskAssessment } = event.authentication || {};
  const riskIsMediumOrHigh = riskAssessment && 
                                  (riskAssessment.confidence === 'high' || 
                                   riskAssessment.confidence === 'medium');

  if (riskIsMediumOrHigh) {
    // ...
  }
}
```

### 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
exports.onExecutePostLogin = async (event, api) => {
  const { riskAssessment } = event.authentication || {};
  const riskIsLow = riskAssessment && riskAssessment.confidence === 'low';

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

### Perform an action if a specific assessment has a specific result

Use the [assessments](#assessments-object) object to access the details for individual assessments, including the `code` property:

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

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

### Aggregate assessments for a custom overall confidence score.

Use the [assessments](#assessments-object) object to access the details for individual assessments, and then use the `confidence` property, the `code` property, or both.

To learn more about custom confidence scoring, read [Custom confidence scoring](#custom-confidence-scoring).

### Block current transaction and return error and message if a specific assessment has a specific result

Use the [assessments](#assessments-object) object 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](/docs/troubleshoot/error-handling-best-practices). The `UnauthorizedError` object always sets `error` to `unauthorized`, but you can customize the `error_message`:

```js lines
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.

### 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](#assessments-object) object to inspect the `code` property for each individual assessment and check if the value is set to `assessment_not_available`.

## 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)
