> ## 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 about best practices for executing Auth0 rules.

# Rules Execution Best Practices

<Warning>
  The End of Life (EOL) date of Rules and Hooks will be **November 18, 2026**, and they are no longer available to new tenants created as of **October 16, 2023**. Existing tenants with active Hooks will retain Hooks product access through end of life.

  We highly recommend that you use Actions to extend Auth0. With Actions, you have access to rich type information, inline documentation, and public `npm` packages, and can connect external integrations that enhance your overall extensibility experience. To learn more about what Actions offer, read [Understand How Auth0 Actions Work](/docs/customize/actions/actions-overview).

  To help with your migration, we offer guides that will help you [migrate from Rules to Actions](/docs/customize/actions/migrate/migrate-from-rules-to-actions) and [migrate from Hooks to Actions](/docs/customize/actions/migrate/migrate-from-hooks-to-actions). We also have a dedicated [Move to Actions](https://auth0.com/extensibility/movetoactions) page that highlights feature comparisons, [an Actions demo](https://www.youtube.com/watch?v=UesFSY1klrI), and other resources to help you on your migration journey.

  To read more about the Rules and Hooks deprecation, read our blog post: [Preparing for Rules and Hooks End of Life](https://auth0.com/blog/preparing-for-rules-and-hooks-end-of-life/).
</Warning>

Each rule is executed as a JavaScript function called in the order defined. The next rule in order won’t execute until the previous rule has completed. In addition, the rule pipeline only executes for workflows that involve user credentials; the rule pipeline **does not** execute during the [Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow). For functionality similar to a rule, an [Action](/docs/customize/actions) in the [Machine to Machine Flow](/docs/customize/actions/explore-triggers/machine-to-machine-trigger) on the `credentials-exchange` trigger can be used instead.

In pipeline terms, a rule completes when the `callback` function supplied to the rule is called. Failure to call the function results in a stall of pipeline execution, and ultimately in an error being returned. Each rule must call the `callback` function **exactly** once.

Rule execution supports the asynchronous nature of JavaScript, and constructs such as [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) objects and the like can be used. Asynchronous processing effectively results in suspension of a pipeline pending completion of the asynchronous operation. An Auth0 serverless Webtask container typically has a circa 20-second execution limit, after which the container may be recycled. Recycling of a container due to this limit will prematurely terminate a pipeline—suspended or otherwise—ultimately resulting in an error in authentication being returned (as well as resulting in a potential reset of the `global` object).

Setting `context.redirect` triggers a redirection once all rules have completed (the redirect is not forced at the point it is set). While all rules must complete within the execution limit of the Webtask container for the redirect to occur, the time taken as part of redirect processing can extend beyond that limit. We recommend that redirection back to Auth0 via the `/continue` endpoint should ideally occur within one hour. Redirection back to the `/continue` endpoint will also cause the creation of a new container in the context of the current pipeline, in which all rules will again be run.

Asynchronous execution will result in a (JavaScript) callback being executed after the asynchronous operation is complete. This callback is typically fired at some point after the main (synchronous) body of a JavaScript function completes. If a rule is making use of asynchronous processing, then a call to the (Auth0) supplied `callback` function must be deferred to the point where asynchronous processing completes and must be the final thing called. As discussed above, the (Auth0) supplied `callback` function must be called exactly once; calling the function more than once within a rule will lead to unpredictable results and/or errors.

## context object

The `context` object provides information about the context in which a rule is run (such as client identifier, connection name, session identifier, request context, protocol, etc). Using the context object, a rule can determine the reason for execution. For example, as illustrated in the sample fragment below, `context.clientID` as well as `context.protocol` can be used to implement conditional processing to determine when rule logic is executed. The sample also shows some best practices for exception handling, use of `npm` modules (for `Promise` style processing), and the `callback` object. To learn more, read [Custom Database Action Script Environment Best Practices](/docs/authenticate/database-connections/custom-db/custom-database-connections-scripts/environment)`.`

```js lines expandable
switch (context.protocol) {
    case 'redirect-callback':
      return callback(null, user, context);
    	break;

    default: {
      user.app_metadata = user.app_metadata || {};
      switch(context.clientID) {
        case configuration.PROFILE_CLIENT: {
          user.user_metadata = user.user_metadata || {};
          Promise.resolve(new
            Promise(function (resolve, reject) {
              switch (context.request.query.audience) {
                case configuration.PROFILE_AUDIENCE: {
                  switch (context.connection) {
                      .
                      .
                  }
                } break;
              .
              .
            })
          )
          .then(function () {
              .
              .
          })
          .catch(function (error) {
            return callback(new UnauthorizedError("unauthorized"), user, context);
          });
        } break;

        default:
          return callback(null, user, context);
          break;

    } break;
```

We highly recommend reviewing best practices when using contextual bypass logic for <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=Multi-Factor+Authentication">Multi-Factor Authentication</Tooltip> checking. For example, **serious security flaws** can surface if use of MFA is predicated on `context.request.query.prompt === 'none'`. In addition, the content of the `context` object is **security sensitive**, so you should **not** directly pass the object to any external or third-party service.

### Redirection

It may not be practical to collect information from a user as part of a login flow in situations where there are many applications and you want a centralized service to manage that, or if you are using a SPA and you want to prevent the user from getting an <Tooltip tip="Access Token: Authorization credential, in the form of an opaque string or JWT, used to access an API." cta="View Glossary" href="/docs/glossary?term=access+token">access token</Tooltip> under certain conditions. In these cases, having a centralized way to collect information or provide a challenge to a user is necessary.

Auth0 allows you to redirect the user to any URL where you can collect information from that user and then return the user to the `/continue` endpoint where they can complete the original /authorize request that triggered the redirect. This is a powerful capability, and depending on the use case, the impact of doing it wrong can be anywhere from innocuous to leaving a security vulnerability in the application. As such, it is important to ensure that this is done correctly.

In most use cases, a redirect rule is in use to prompt the user to make some change to their profile such as:

* Forcing a password change
* Verifying their email
* Adding information to their profile

We recommend that the rule check for some flag or value in the user's `app_metadata`, then redirect to an application that does its own /authorize call to Auth0 and make any changes to the user's metadata and redirect the user back to Auth0. This works great for any profile changing redirects or anything that does not need to restrict the user from logging in.

Redirect from rule allows you to implement custom authentication flows that require additional user interaction triggered by context.redirect. Redirect from rule can only be used when calling the `/authorize` endpoint.

Redirection to your own hosted user interface is performed before a pipeline completes and can be triggered once per `context.clientID` context. Redirection should only use HTTPS when executed in a production environment, and additional parameters should be kept to a minimum to help mitigate common security threats. Preferably, the Auth0-supplied `state` is the only parameter supplied.

Once redirected, your own hosted user interface executes in a user authenticated context, and obtains authenticity artifacts by the virtue of Auth0 <Tooltip tip="Single Sign-On (SSO): Service that, after a user logs into one applicaton, automatically logs that user in to other applications." cta="View Glossary" href="/docs/glossary?term=SSO">SSO</Tooltip>. Obtaining these artifacts—e.g., an <Tooltip tip="Single Sign-On (SSO): Service that, after a user logs into one applicaton, automatically logs that user in to other applications." cta="View Glossary" href="/docs/glossary?term=ID+Token">ID Token</Tooltip> in <Tooltip tip="OpenID: Open standard for authentication that allows applications to verify users' identities without collecting and storing login information." cta="View Glossary" href="/docs/glossary?term=OpenID">OpenID</Tooltip> Connect (OIDC), and/or an Access Token in <Tooltip tip="OpenID: Open standard for authentication that allows applications to verify users' identities without collecting and storing login information." cta="View Glossary" href="/docs/glossary?term=OAuth+2.0">OAuth 2.0</Tooltip>—is achieved by using a `context.clientID` context **that is not** the one which triggered redirect. To do this, redirect to the `/authorize` endpoint. In the case of a SPA for example, use silent authentication. This creates a new pipeline that causes all rules to execute again, and you can use the `context` object within a rule to perform conditional processing.

Upon completion of whatever processing is to be performed, pipeline execution continues by redirecting the user back to Auth0 via the `/continue` endpoint (and specifying the `state` supplied). This causes all rules to execute again within the current pipeline, and you can use the `context` object within a rule to perform conditional processing checks.

Beware of storing too much data in the Auth0 profile. This data is intended to be used for authentication and authorization purposes. The metadata and search capabilities of Auth0 are not designed for marketing research or anything else that requires heavy search or update frequency. Your system is likely to run into scalability and performance issues if you use Auth0 for this purpose. A better approach is to store data in an external system and store a pointer (the user ID) in Auth0 so that backend systems can fetch the data if needed. A simple rule to follow is to store only items that you plan to use in rules to add to tokens or make decisions.

Passing information back and forth in the front channel opens up surface area for <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+actors">bad actors</Tooltip> to attack. This should definitely be done only in conditions where you must take action in the rule (such as rejecting the authorization attempt with `UnauthorizedError`).

## user object

The `user` object provides access to a cached copy of the user account (user profile) record in Auth0. The object provides access to information regarding the user without the need to access the Auth0 <Tooltip tip="Management API: A product to allow customers to perform administrative tasks." cta="View Glossary" href="/docs/glossary?term=Management+API">Management API</Tooltip>—access which is both rate limited and subject to latency.

While the contents of the `user` object can be modified—for example, one rule could make a change which another rule could use to influence its execution—any changes made will not be persisted. There may be occasions when it becomes necessary to persist, say, updates to metadata associated with a user, and the `auth0` object can be used to perform such operations where required.

Updating a user via use of the `auth0` object ultimately results in a call to the Auth0 Management API. As the Auth0 Management API is both rate limited and subject to latency, caution should be exercised regarding when and how often updates are performed.

The `context` object contains the `primaryUser` property which refers to the user identifier of the primary user. This user identifier will typically be the same as `user_id` property in the root of the `user` object. The primary user is the user that is returned to the Auth0 engine when the rule pipeline completes, and the `user_id` is a unique value generated by Auth0 to uniquely identify the user within the Auth0 tenant. This `user_id` should be treated as an opaque value.

There are occasions when `primaryUser` must be updated as the primary user may change—i.e., the user returned to the Auth0 engine will be different from the user on rule pipeline entry. On such occasions, a rule must update `primaryUser` to reflect the new primary user identifier. Note that this change will not affect any subsequent rule executed in the current instance of the pipeline; the `user` object will remain unchanged.

### Identities

The `user` object also contains a reference to the identities associated with the user account. The `identities` property is an array of objects, each of which contain properties associated with the respective identity as known to the <Tooltip tip="Identity Provider (IdP): Service that stores and manages digital identities." cta="View Glossary" href="/docs/glossary?term=identity+provider">identity provider</Tooltip> (for example, the `provider` name, associated `connection` in Auth0, and the `profileData` obtained from the identity provider during the last authentication using that identity). Linking user accounts creates multiple entries in the array.

Each identity in the `identities` array also contains a `user_id` property. This property is the identifier of the user as known to the identity provider. While the `user_id` property in the root of the `user` object may also include the identifier of the user as known to the identity provider, as a best practice, use of the `user_id` property in an array identity should be preferred. The `user_id` in the root of the user object should be treated as an opaque value and should not be parsed.

### Metadata

The `user_metadata` property and the `app_metadata` property refer to the two different aspects of the metadata associated with a user. Both the `user_metadata` property and the `app_metadata` property provide access to cached copies of each.

Authorization-related attributes for a user—such as role(s), group(s), department, and job codes—should be stored in `app_metadata` and not `user_metadata`. This is because `user_metadata` can essentially be modified by a user, whereas `app_metadata` cannot.

There may be occasions when it becomes necessary to persist, say, updates to metadata associated with a user, and the `auth0` object can be used to perform such operations where required. When updating either metadata object, it is important to be judicious regarding what information is stored: in line with metadata best practice, be mindful of excessive use of metadata, which can result in increased latency due to excessive processing within the pipeline. To learn more, read [Metadata Field Names and Data Types](/docs/manage-users/user-accounts/metadata/metadata-fields-data). Use of the `auth0` object also results in a call to the Auth0 Management API, so caution should be exercised regarding when and how often updates are performed since the Auth0 Management API is both rate limited and subject to latency.

## callback function

The `callback` function supplied to a rule effectively acts as a signal to indicate completion of the rule. A rule should complete immediately following a call to the callback function, either implicitly or by explicitly executing a (JavaScript) `return` statement, and should refrain from any other operation.

Failure to call the function will result in a stall of pipeline execution, and ultimately in an error condition being returned. Each rule then must call the `callback` function exactly once. Calling it once prevents the stall of the pipeline, but more could cause unpredictable results or errors.

```javascript lines
function (user, context, callback) {
  getRoles(user.user_id, (err, roles) => {
    if (err) return callback(err);

    context.idToken['https://example.com/roles'] = roles;

    return callback(null, user, context);
  });
}
```

As can be seen in the example above, the `callback` function can be called with up to three parameters. The first parameter is mandatory and provides an indication of the status of rule operation. The second and third parameters are optional and represent the user and the context to be supplied to the next rule in the pipeline. If these are specified, then it is a recommended best practice to pass the `user` and `context` object (respectively) as supplied to the rule.

While it can be acceptable to modify certain contents of either the `user` or the `context` object for certain situations, as a recommended best practice you should refrain from passing a newly-created instance of either the `user` or the `context` object. Passing anything other than a `user` or `context` object will have unpredictable results and may lead to an exception or error condition.

The status parameter should be passed as either `null`, an instance of an `Error` object, or an instance of an `UnauthorizedError` object. Specifying null will permit the continuation of pipeline processing, while any of the other values will terminate the pipeline; an `UnauthorizedError` signals denial of access and allows information to be returned to the originator of the authentication operation regarding the reason why access is denied. Passing any other value for any of these parameters will have unpredictable results and may lead to an exception or error condition.

As authentication has already occurred, any early exit of the pipeline with an (authorization) error will not impact the authenticated session within the browser; subsequent redirects to /authorize will typically result in an automatic login. The early exit of the pipeline simply stops tokens et al from being generated. One option is for the application to redirect to the Authentication API's [Logout endpoint](https://auth0.com/docs/api/authentication#logout), if required, to force termination of the Auth0 session in the browser.

Any call to the Logout endpoint could be interrupted, so explicit Auth0 session termination is not guaranteed. This is important, as any explicit condition that caused an `unauthorized` error must be re-checked in any subsequent rule pipeline execution, and it should not be possible to bypass these condition check(s) through any other conditions (such as `prompt===none`).

## Learn more

* [Rules Anatomy Best Practices](/docs/rules-best-practices/rules-anatomy-best-practices)
* [Rules Environment Best Practices](/docs/rules-best-practices/rules-environment-best-practices)
* [Rules Security Best Practices](/docs/rules-best-practices/rules-security-best-practices)
* [Rules Testing Best Practices](/docs/rules-best-practices/rules-testing-best-practices)
* [Error Handling Best Practices](/docs/troubleshoot/error-handling-best-practices)
