---
name: azion-protect-a-route-with-an-altcha-challenge
description: >-
  Run the ALTCHA challenge on a firewall, then add the application rule that sends unverified requests to it.
---

# Protect a route with an ALTCHA challenge

ALTCHA is an open-source CAPTCHA alternative that keeps bots and spam off a protected route. It answers a request with a challenge, and it runs as a function on a firewall. A rule on the application sends unverified requests to the challenge. Every step runs in Azion Console.

The function adds two endpoints to the application. `/az-request-verify` returns the challenge page, and `/az-request-captcha` validates the solution. A browser that solves the challenge receives a session cookie, so later requests pass without a new challenge.

ALTCHA runs inside Azion infrastructure and calls no third-party service. It collects no personal data, and the widget works with screen readers and other assistive technologies.

To run ALTCHA as the redirect target of Bot Manager, refer to [Firewall best practices](/en/documentation/platform/firewall/best-practices/#bot-manager).

---

## Prerequisites

- An Azion account. To create one, refer to [How to create an account on Azion](/en/documentation/fundamentals/creating-account/).
- The ALTCHA function on your account. ALTCHA is an integration from Azion Marketplace. To install it, refer to [How to install an integration](/en/documentation/guides/application-development/integrations/install-an-integration/).
- The **Edit Firewall** permission on the account. It grants permission to view, create, edit, and remove a firewall, and it also requires the permission **View Firewall**.
- The **Edit Applications** permission on the account. The redirect rule changes an application, and this permission also requires the permission **View Applications**. Refer to [Teams Permissions](/en/documentation/fundamentals/teams-permissions/).
- An application, and the route the challenge protects. The examples use `/form` as that route.

> **Caution**
>
> Computing time and invocations for functions generate usage-related costs. For the rates, refer to [Pricing](/en/documentation/fundamentals/pricing/).

---

## Create the firewall

ALTCHA runs on a firewall with the **Functions** module turned on. To create the firewall:

1. **Open the Firewall page**

   Access [Azion Console](https://console.azion.com/) > **Firewall**.

2. **Select + Firewall**

3. **Name the firewall**

   Enter a name for the firewall. For example: `altcha firewall`.

4. **Turn on the Functions module**

5. **Select Save**

The firewall is saved, and the **Functions Instances** and **Rules Engine** tabs become available on the same page.

> **Note**
>
> To use a firewall that already exists, open it and turn on the **Functions** module in the **Main Settings** tab.

---

## Instantiate the ALTCHA function

A function instance binds ALTCHA to one firewall and carries its configuration. To create the instance:

1. **Go to the Functions Instances tab**

   In the firewall you created, go to the **Functions Instances** tab.

2. **Select + Function Instance**

3. **Name the instance**

   Enter a name for the instance. For example: `altcha instance`.

4. **Select the ALTCHA function**

   In the function list, select **ALTCHA**. The **Arguments** tab loads.

5. **Enter the arguments**

   (Optional) In the **Arguments** tab, enter the configuration in JSON. Every parameter is optional, and the function uses its default for each parameter you omit. For example:

   ```json
   {
     "cookie_max_age": 1800,
     "captcha_localization": {
       "label": "Verify that you are human"
     },
     "captcha_colors": {
       "base": "#f8f9fa",
       "border": "#dee2e6",
       "text": "#495057"
     }
   }
   ```

   For each parameter the function accepts, refer to [Configuration parameters](#configuration-parameters).

6. **Select Save**

The instance appears in the **Functions Instances** tab. It does not run until a Rules Engine rule selects it.

---

## Add the firewall rule that runs ALTCHA

A [Rules Engine](/en/documentation/platform/firewall/rules-engine/) rule sets when the firewall runs ALTCHA. The criteria cover the protected route and both ALTCHA endpoints. To add the rule:

1. **Go to the Rules Engine tab**

   In the same firewall, go to the **Rules Engine** tab.

2. **Select + Rules Engine**

3. **Name the rule**

   Enter a unique, descriptive name. For example: `Run ALTCHA`.

4. **Set the criteria**

   In the **Criteria** section, match the **Request URI** against `/form`, `/az-request-verify`, and `/az-request-captcha`. Replace `/form` with the route the challenge protects, such as `/api/submit`.

5. **Select the behavior**

   In the **Behavior** section, select **Run Function** and then the ALTCHA instance.

6. **Keep Status as Active**

7. **Select Save**

The firewall runs ALTCHA on every request whose URI matches the criteria. Changes can take a few minutes to propagate.

---

## Add the application rule that starts the challenge

The application starts the flow. A request to the protected route without the `X-Azcaptcha-Success` header goes to `/az-request-verify`. To add the rule in the [Rules Engine](/en/documentation/platform/applications/rules-engine/) of the application:

1. **Open the application**

   In Azion Console, go to **Applications** and select the application the challenge protects.

2. **Go to the Rules Engine tab**

3. **Select + Rule**

4. **Name the rule**

   Enter a unique, descriptive name. For example: `Start ALTCHA challenge`.

5. **Select the request phase**

   Set **Phase** to *Request*.

6. **Add the first criterion**

   In the **Criteria** section, select the `${http_X_Azcaptcha_Success}` variable and the `does not exist` operator.

7. **Add the second criterion**

   Select the `${uri}` variable, the `is equal` operator, and `/form` as the value.

8. **Set the redirect behavior**

   In the **Behavior** section, select **Redirect To (302 Found)** and enter `/az-request-verify` as the destination.

9. **Keep Status as Active**

10. **Select Save**

A request to `/form` without a valid session cookie now goes to the ALTCHA challenge page. The verification flow starts there.

---

## Customize the challenge page

By default, ALTCHA serves a white page that holds the widget. Three parameters change it: `custom_html` replaces the page, `captcha_colors` sets the colors of the widget, and `captcha_localization` sets its text.

To replace the page, set `custom_html` in the **Arguments** tab of the instance:

```json
{
  "custom_html": "<!DOCTYPE html><html><head><title>Verification</title></head><body><h1>Complete the challenge</h1>{/* azion_captcha */}</body></html>"
}
```

> **Tip**
>
> Include the `{/* azion_captcha */}` marker in the HTML. It sets where the function inserts the ALTCHA widget. Without the marker, the widget goes at the end of the HTML body.

To show the widget messages in the language of your users, set `captcha_localization`:

```json
{
  "captcha_localization": {
    "error": "Verification error. Try again.",
    "label": "Verify that you are human",
    "verifying": "Verifying...",
    "verified": "Successfully verified!"
  }
}
```

---

## Configuration parameters

The **Arguments** tab of the instance takes a JSON object. Every parameter is optional:

```json
{
  "allowed_domains": ["my-website.azion.app", "third-party.azion.app"],
  "cookie_secret": "string",
  "cookie_max_age": 86400,
  "status_code": 200,
  "captcha_localization": {
    "error": "Custom error message",
    "label": "Widget text",
    "verifying": "Verifying...",
    "verified": "Verified!"
  },
  "captcha_colors": {
    "base": "#ffffff",
    "border": "#cccccc",
    "border_focus": "#007bff",
    "text": "#333333",
    "error_text": "#dc3545"
  },
  "custom_html": "Custom HTML"
}
```

Each parameter, its type, and its default:

| Parameter                        | Type             | Default                                   | Description                                                                                                                                                                                                                                                              |
| -------------------------------- | ---------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `allowed_domains`                | Array of strings | `${host}`                                 | Sets the domains the function allows redirects to. The host of the application and relative redirects are always allowed. On an invalid value, the function ignores the parameter and logs a warning in [Real-Time Events](/en/documentation/platform/real-time-events/) |
| `captcha_colors`                 | Object           | None                                      | Sets the colors of the ALTCHA widget                                                                                                                                                                                                                                     |
| `captcha_colors.base`            | String           | Defined by ALTCHA                         | Base color of the ALTCHA widget, as a hex triplet                                                                                                                                                                                                                        |
| `captcha_colors.border`          | String           | Defined by ALTCHA                         | Border color of the ALTCHA widget, as a hex triplet                                                                                                                                                                                                                      |
| `captcha_colors.border_focus`    | String           | Defined by ALTCHA                         | Border color of the ALTCHA widget while it holds focus, as a hex triplet                                                                                                                                                                                                 |
| `captcha_colors.error_text`      | String           | Defined by ALTCHA                         | Color of the error messages in the ALTCHA widget, as a hex triplet                                                                                                                                                                                                       |
| `captcha_colors.text`            | String           | Defined by ALTCHA                         | Text color of the ALTCHA widget, as a hex triplet                                                                                                                                                                                                                        |
| `captcha_localization`           | Object           | None                                      | Sets the strings the ALTCHA widget shows                                                                                                                                                                                                                                 |
| `captcha_localization.error`     | String           | Defined by ALTCHA                         | Message shown when an error occurs while the user solves the challenge                                                                                                                                                                                                   |
| `captcha_localization.label`     | String           | Defined by ALTCHA                         | Message shown beside the checkbox the user selects                                                                                                                                                                                                                       |
| `captcha_localization.verified`  | String           | Defined by ALTCHA                         | Message shown after the widget detects a correct solution. The script redirects the user on a correct solution, so most users never see it                                                                                                                               |
| `captcha_localization.verifying` | String           | Defined by ALTCHA                         | Message shown while the script verifies the solution                                                                                                                                                                                                                     |
| `cookie_max_age`                 | Integer          | `86400`                                   | Sets the maximum age for the session cookie. A short value causes frequent challenges, and a long value reduces security                                                                                                                                                 |
| `cookie_secret`                  | String           | `@z10N!${FUNCTION_VERSION}`               | Secret key that signs the session cookie                                                                                                                                                                                                                                 |
| `custom_html`                    | String           | A white page that holds the ALTCHA widget | Replaces the layout of the challenge page. The function inserts the widget at the `{/* azion_captcha */}` tag, or at the end of the HTML body when the tag is absent                                                                                                     |
| `status_code`                    | Integer          | `200`                                     | Sets the status code of the challenge page response. On an invalid value, or on a status code that allows no response body such as 101, 204, 205, or 304, the function uses `200`                                                                                        |

> **Caution**
>
> Configure `allowed_domains` on every ALTCHA Redirect instance. The parameter sets the domains the function allows redirects to, and it protects users against open redirects. For the version that introduced it, refer to [Changelog](/en/documentation/changelog/).

---

## Control headers and session cookies

ALTCHA sets HTTP headers that carry the state of the verification. Use them to debug the flow and to drive the logic of your application.

| Header                        | Description                                              |
| ----------------------------- | -------------------------------------------------------- |
| `X-Azcaptcha-Success: true`   | The user solved the challenge                            |
| `X-Azcaptcha-Violation: true` | The function detected an attempt to bypass the challenge |

ALTCHA also sets two cookies that hold the state of the verification session.

| Cookie                                  | Description                                                                     |
| --------------------------------------- | ------------------------------------------------------------------------------- |
| `az_${FUNCTION_VERSION}_verify_payload` | The raw data of the challenge solution                                          |
| `az_${FUNCTION_VERSION}_verify_session` | The signed session cookie that validates later requests without a new challenge |

Monitor the function logs in [Real-Time Events](/en/documentation/platform/real-time-events/) for bypass attempts, and adjust the configuration on what the logs show.

---

## Limitations

- **HTTPS**: ALTCHA uses the Web Crypto API, and that API runs only over HTTPS.
- **Full URLs**: a redirect parameter carries the scheme and the hostname.
- **Reserved endpoints**: `/az-request-verify` and `/az-request-captcha` serve ALTCHA only. The application must not use a URL that carries either term.

---

## Next steps

- [Run a function on a firewall](/en/documentation/guides/application-development/functions-and-runtime/firewall.md): Write your own firewall function, instantiate it, and add the rule that triggers it.
- [Instantiate a function on a firewall](/en/documentation/guides/application-security/firewall-and-waf/instantiate-functions.md): Create the same instance from the Azion API, and pass its Args in JSON.
- [Rules Engine for Firewall](/en/documentation/platform/firewall/rules-engine.md): Every criteria variable, comparison operator, and behavior a firewall rule accepts.
- [Firewall best practices](/en/documentation/platform/firewall/best-practices.md#bot-manager): Send traffic classified as suspicious to the ALTCHA challenge page.
- [Block account takeover on login and checkout flows](/en/documentation/use-cases/secure-applications-and-networks/block-account-takeover-on-login-and-checkout-flows.md): A design where Bot Manager sends flagged clients on login and signup to this challenge.
