> ## Documentation Index
> Fetch the complete documentation index at: https://auth0-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Learn how to customize authentication flows by redirecting users using rules. Example areas that can be customized include MFA, privacy policy acceptance, and gathering user data.

# Redirect Users from Within Rules

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

<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/platform/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>

You can use [Auth0 Rules](/docs/customize/rules) to redirect users before an authentication transaction is complete. This lets you implement custom authentication flows that require additional user interaction beyond the standard login form. Redirect rules are commonly used to do custom <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> (MFA) in Auth0, but they can also be used for:

* Custom privacy policy acceptance, terms of service, and data disclosure forms.
* Securely performing a one-time collection of additional required profile data.
* Allowing remote Active Directory users to change their password.
* Requiring users to provide additional verification when logging in from unknown locations.
* Gathering more information about your users than they provided at initial signup.

You can redirect a user **once** per authentication flow. If you have one rule that redirects a user, you **cannot** invoke a second rule to redirect the user at a later time.

To learn more, see [Multi-Factor Authentication in Auth0](/docs/secure/multi-factor-authentication).

## Start redirect and resume authentication

Set the `context.redirect` property as follows:

```javascript lines theme={null}
function (user, context, callback) {
  context.redirect = {
    url: "https://example.com/foo"
  };
  return callback(null, user, context);
}
```

Once all rules have finished executing, Auth0 redirects the user to the URL specified in the `context.redirect.url` property. Auth0 also passes a `state` parameter in that URL. For example:

```http lines theme={null}
https://example.com/foo?state=abc123
```

Your redirect URL needs to extract the `state` parameter and send it back to Auth0 to resume the authentication transaction. State is an opaque value, used to prevent [Cross-Site Request Forgery (CSRF) attacks](/docs/secure/security-guidance/prevent-threats#cross-site-request-forgery).

After the redirect, resume authentication by redirecting the user to the `/continue` endpoint and include the `state` parameter you received in the URL. If you do not send the original state back to the `/continue` endpoint, Auth0 will lose the context of the login transaction and the user will not be able to log in due to an `invalid_request` error.

For example:

export const codeExample1 = `https://{yourDomain}/continue?state={originalState}`;

<AuthCodeBlock children={codeExample1} language="http" />

If you're using a <Tooltip tip="Custom Domain: Third-party domain with a specialized, or vanity, name." cta="View Glossary" href="/docs/glossary?term=custom+domain">custom domain</Tooltip>:

```http lines theme={null}
https://{yourAuth0CustomDomain}/continue?state={originalState}
```

`THE_ORIGINAL_STATE` is the value that Auth0 generated and sent to the redirect URL. For example, if your rule redirected to `https://example.com/foo`, Auth0 would use a redirect URL similar to `https://example.com/foo?state=abc123`. So `abc123` would be the `THE_ORIGINAL_STATE`. To resume the authentication transaction, you would redirect to:

export const codeExample2 = `https://{yourDomain}/continue?state=abc123`;

<AuthCodeBlock children={codeExample2} language="http" />

When a user has been redirected to the `/continue` endpoint:

* **all rules will be run again**, however, the `context.redirect` will be ignored to allow authentication to continue.
* any changes to the user object are made during the redirect, prior to calling the `/continue` endpoint. For example, updates through 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> are available after continuing the transaction.

## Validate resumed login

To distinguish between user-initiated logins and resumed login flows, check the `context.protocol` property:

```javascript lines theme={null}
function (user, context, callback) {
    if (context.protocol === "redirect-callback") {
        // User was redirected to the /continue endpoint
    } else {
        // User is logging in directly
    }
}
```

## Force password change example

In some cases, you may want to force users to change their passwords under specific conditions. You can write a rule that has the following behavior:

1. The user attempts to log in and needs to change their password.
2. The user is redirected to an application-specific page with a JWT in the query string. This JWT ensures that only this user's password can be changed and **must be validated** by the application.
3. The user changes their password in the application-specific page by having the application call the [Auth0 Management API](https://auth0.com/docs/api/management/v2/users/patch-users-by-id)
4. Once the user has successfully changed their password, the application extracts the `authorize_again` claim from the verified and decoded JWT, then proceeds to redirect the user to that URL allowing them to sign in with their new password.

```javascript lines expandable theme={null}
function(user, context, callback) {
   /*
   * Prerequisites:
   * 1. Implement a `mustChangePassword` function
   * 2. Set configuration variables for the following:
   *    - CLIENT_ID
   *    - CLIENT_SECRET
   *    - ISSUER
   */

  const url = require('url@0.10.3');
  const req = context.request;

  function mustChangePassword() {
    // TODO: implement function
    return true;
  }

  if (mustChangePassword()) {
    // User has initiated a login and is forced to change their password
    // Send user's information and query params in a JWT to avoid tampering
    function createToken(clientId, clientSecret, issuer, user) {
      const options = {
        expiresInMinutes: 5,
        audience: clientId,
        issuer: issuer
      };
      return jwt.sign(user, clientSecret, options);
    }

    const token = createToken(
      configuration.CLIENT_ID,
      configuration.CLIENT_SECRET,
      configuration.ISSUER,
      {
        sub: user.user_id,
        email: user.email,
        authorize_again: url.format({
          protocol: 'https',
          hostname: auth0.com,
          pathname: '/authorize',
          query: req.query
        })
      }
    );

    context.redirect = {
      url: `https://example.com/change-pw?token=${token}`
    };
  }

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

## Where to store data

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.

## Security considerations

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`).

If, however, you need to communicate directly back to Auth0 and give it instructions for restricting access (you are implementing CAPTCHA checks or custom MFA), then you must have a way to securely tell Auth0 that the requirements of that operation were performed. Likewise, if you need to hand information to the application that you are redirecting to, then you must have a secure way to ensure that the information transferred has not been tampered with.

### Ensure app is logging into the same user

The application is going to redirect the user back to the Auth0 tenant, so any data related to the user can be gathered through the <Tooltip tip="ID Token: Credential meant for the client itself, rather than for accessing a resource." cta="View Glossary" href="/docs/glossary?term=ID+token">ID token</Tooltip> that is returned to the application. However, you may want to ensure that the application is logging into the same user that is being redirected from to ensure that there is no tampering of any sort in-between. Therefore you will likely want to send a token along with the request.

The token sent to the app should have the following requirements:

| Token Element | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sub`         | The Auth0 `user_id` of the user.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `iss`         | An identifier that identifies the rule itself.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `aud`         | The application that is targeted for the redirect.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `jti`         | A randomly generated string that is stored for confirmation in the user object (in the rule code, set user.jti = uuid.v4(); and then add it as a jti to the token you create). user.jti will still be set when rules run again when /continue is called. This is inline with specifications.                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `exp`         | Should be as short as possible to avoid re-use of the token.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `other`       | Any other custom claims information you need to pass.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `signature`   | Assuming that the application has a secure place to store a secret, you can use HS256 signed signatures. This greatly reduces the complexity of the solution and since the token being passed back will have to be signed as well, this is a requirement of this solution. You can use RS256, but it requires the creating of a certificate and updating that certificate when it expires. If you are not passing any information directly back to the rules, then you could use an SPA for this intermediate app and then may prefer RS256 so that the application doesn't have to store the info. It would require you to have a way to validate the token, either through an introspection endpoint or through a public JWKS endpoint. |

<Warning>
  This token should **not** be treated as a Bearer token! It is a signed piece of information for use in the application. The application should still redirect back to Auth0 to authenticate the user.
</Warning>

### Pass information back to the rule

In most scenarios, even if you want to pass information from the rule to the application. The application will hopefully be able to safely store the information in whatever storage is necessary. Even if the idea is to update the app or user metadata in Auth0, that can be done using the management API and the user information will be updated as long as it has been completed before redirecting the user back to the `/continue` endpoint. Only if the rule itself must get information and that information is only relevant to this particular sign in session should you pass information back to the rule.

When passing information back to the `/continue` endpoint, the token passed should have the following requirements:

| Token Element | Description                                                                                                                                                                                                                                                                                                                                                                                |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `sub`         | The Auth0 `user_id` of the user.                                                                                                                                                                                                                                                                                                                                                           |
| `iss`         | The application that is targeted for the redirect.                                                                                                                                                                                                                                                                                                                                         |
| `aud`         | Some identifier that identifies the rule itself.                                                                                                                                                                                                                                                                                                                                           |
| `jti`         | The same JTI that was stored in the token passed to the application (NOTE: it should match user.jti or fail).                                                                                                                                                                                                                                                                              |
| `exp`         | Should be as short as possible to avoid reuse of the token.                                                                                                                                                                                                                                                                                                                                |
| `other`       | Any other custom claims information you need to pass.                                                                                                                                                                                                                                                                                                                                      |
| `signature`   | Assuming that the application has a secure place to store a secret, you can use HS256 signed signatures. This greatly reduces the complexity of the solution and since the token being passed back will have to be signed as well, this is a requirement of this solution. You can use RS256, but it requires the creating of a certificate and updating that certificate when it expires. |

It should be sent using POST and then fetched at `context.request.body.token` (or something similar) rather than passing it as a query parameter. This is similar to the form-post method for authentication.

If you are not passing information back to the `/continue` endpoint, you may want to denylist the JTI unless your expiration times are short enough that replay attacks will be almost impossible.

## Restrictions and limitations

Redirect Rules won't work with:

* [Resource Owner endpoint](https://auth0.com/docs/api/authentication/reference#resource-owner)
* [Password exchange](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow)
* [Refresh Token exchange](/docs/secure/tokens/refresh-tokens)

You can detect the above cases by checking `context.protocol`:

* For Password exchange: `context.protocol === 'oauth2-password'`
* For <Tooltip tip="Refresh Token: Token used to obtain a renewed Access Token without forcing users to log in again." cta="View Glossary" href="/docs/glossary?term=Refresh+Token">Refresh Token</Tooltip> exchange: `context.protocol === 'oauth2-refresh-token'`
* For <Tooltip tip="Resource Owner: Entity (such as a user or application) capable of granting access to a protected resource." cta="View Glossary" href="/docs/glossary?term=Resource+Owner">Resource Owner</Tooltip> logins: `context.protocol === 'oauth2-resource-owner'`

### Session timeout

Redirect rule sessions are normally valid for 3 days unless you have configured a shorter timeout in your **Login Session Management** settings. You can find these settings in your [tenant's advanced settings](https://manage.auth0.com/#/tenant/advanced).

### Resource Owner endpoint

It is impossible to use redirect rules in the context where you are calling `/oauth/token` directly for the Resource Owner Password Grant. Since the user is not in a redirect flow to begin with, you can not redirect the user in a rule. If you attempt to set context.redirect you will get a failed login attempt with the error interaction\_required.

### Flows where prompt=none

Since the goal of `prompt=none` is to avoid any scenario where the user will be required to enter input, any redirection will result in an `error=interaction_required`.

Since rules run after an authentication session is created, you cannot use `prompt=none` if you have a redirect rule that is attempting to block access to tokens under certain conditions (custom MFA, CAPTCHA with login, etc.).

You cannot create a redirect flow that blocks token access and bypasses the redirect rule if `prompt=none` because after a failed attempt, a user can simply call again with `prompt=none` and get tokens because their authentication session has been created even though rules failed the first time.

### Refresh tokens

Due to the fact that using a refresh token requires a backchannel call to `/oauth/token`, this will also fail if you set `context.redirect`.

It is difficult to securely verify that any restrictions on login were carried out. There is not a consistent session ID in the context that could be used to collect information associated with the session such as this user passed MFA challenges. Therefore, you cannot use `prompt=none` at all.

Anytime `context.redirect` is set in a rule, if `prompt=none` was passed, then the authorization fails with `error=interaction_required`, but since the user's session is created even if rules fail, we can't trust that a user passed all `context.redirect` challenges and therefore can't use `prompt=none` as a way to get tokens.

In this specific case, we recommend that you use refresh tokens exclusively, because you can ensure that a user passed challenges if those challenges are required to generate a refresh token.

## Learn more

* [Redirect Users](/docs/authenticate/login/redirect-users-after-login)
* [Understand How Progressive Profiling Works](/docs/manage-users/user-accounts/user-profiles/progressive-profiling)
* [Redirect Users with Alternative Logout](/docs/authenticate/login/logout/redirect-users-after-logout)
