> ## Documentation Index
> Fetch the complete documentation index at: https://ngrok.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Support Multiple Authentication Methods with Traffic Policy

> Support multiple ways for your users to connect to upstream services with a flexible OR Operator pattern.

export const domain_0 = undefined

Some services need to support different groups of users with different types of credentials.
Internal teams might use static IPs, but external users authenticate using Basic Auth.
With ngrok’s Traffic Policy engine, you can let both types of users through safely without making any changes to your upstream service.

This example walks you through how to apply multiple authentication layers to a single endpoint using [action result variables](/traffic-policy/variables/action/) and expressions that mimic an `OR` Operator.
You'll allow requests from trusted IPs `OR` those with valid Basic Auth credentials, and then reject all others.

## 1. Start an endpoint for your service

Start an internal [Agent Endpoint](/gateway/agent-endpoints/), replacing `$PORT` based on where your service listens.
You can also use one of the [SDKs](/agent-sdks) or the [Kubernetes Operator](/k8s).

```bash theme={null}
ngrok http $PORT --url https://service.internal
```

## 2. Reserve a domain

Navigate to the [**Domains** section](https://dashboard.ngrok.com/domains) of the ngrok dashboard and click **New +** to reserve a free static domain like {<code>{domain_0}</code> || `https://your-service.ngrok.app`} or a [custom domain](/gateway/custom-domains/) you already own.

We'll refer to this domain as `$NGROK_DOMAIN` from here on out.

## 3. Create a Cloud Endpoint

Navigate to the [**Endpoints** section](https://dashboard.ngrok.com/endpoints?sortBy=updatedAt\&orderBy=desc) of the ngrok dashboard, then click **New +** and **Cloud Endpoint**.

In the **URL** field, enter the domain you just reserved to finish creating your [Cloud Endpoint](/gateway/cloud-endpoints/).

## 4. Add layers of authentication with Traffic Policy

While viewing your new Cloud Endpoint in the dashboard, copy the policy below and paste it into the Traffic Policy editor.
You will need to change:

* `$TRUSTED_IP_FOO`/`$TRUSTED_IP_BAR`: Replace with public IPs of those who should have access to your service or an [IP policy](https://dashboard.ngrok.com/ip-restrictions) in your ngrok dashboard.

```yaml theme={null}
on_http_request:
  # Check whether a request's IP matches your allow list.
  - actions:
      - type: restrict-ips
        config:
          # By specifying `false`, you allow the action to run and generate
          # response variables, like `action.ngrok.restrict_ips.action, which
          # allow you to more precisely customize how your policy responds.
          enforce: false
          allow:
            - $TRUSTED_IP_FOO/32
            - $TRUSTED_IP_BAR/32

  # If IP restriction fails, try Basic Auth
  - expressions:
      - actions.ngrok.restrict_ips.action == "deny"
    actions:
      - type: basic-auth
        config:
          enforce: false
          credentials:
            - user:password1
            - admin:password2

  # Forward the request if either the IP restriction OR the Basic Auth actions were successful.
  - expressions:
      - "actions.ngrok.restrict_ips.action == 'allow' || actions.ngrok.basic_auth.credentials.authorized == true"
    actions:
      - type: forward-internal
        config:
          url: https://service.internal

  # Catch-all custom response for any unauthenticated requests.
  - actions:
      - type: custom-response
        config:
          status_code: 401
          headers: {}
          body: >-
            <!DOCTYPE html>
            <html lang="en">
            <head>
              <meta charset="UTF-8" />
              <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
              <title>Unauthorized</title>
              <style>
                body{margin:0;height:100vh;background-color:#f9f9f9;display:flex;align-items:center;justify-content:center;font-family:system-ui,sans-serif}.box{padding:2rem 3rem;border:2px solid #d9534f;border-radius:12px;background-color:#fff3f3;color:#d9534f;font-size:1.5rem;text-align:center;box-shadow:0 4px 12px rgba(0,0,0,.1)}
              </style>
            </head>
            <body>
              <div class="box">
                🚫 Access denied
              </div>
            </body>
            </html>
```

**What's happening here?**
The first section of this policy checks every HTTP request to see if its source IP matches one on your `allow` list for `restrict-ips`, but doesn't actually enforce the restriction there.
Instead, the expression that follows the first action checks whether the [`restrict-ips` action result variable](/traffic-policy/actions/restrict-ips/#action-result-variables) `actions.ngrok.restrict_ips.action` is set to `allow`, which means that it would've allowed the request directly if you had set `enforce: true`.

If it's false—the request didn't match the IP `allow` list—then the policy then validates whether it contains a valid Basic Auth header.

Next, the policy checks whether either IP restrictions `OR` Basic Auth were successful, and if so, forwards to your upstream service.

A catch-all rule then sends a custom error response to all other requests.

## 6. Try out your endpoint

Visit the domain you reserved either in the browser or in the terminal using a tool like `curl`.
You should see the app or service at the port connected to your internal Agent Endpoint.

Add base64-encoded `username:password` pair as an `Authorization: Bearer` header to verify your `basic-auth` action works as expected.

```bash theme={null}
curl https://$NGROK_DOMAIN \
  --header 'Authorization: Bearer $BASE64_CREDENTIALS'
```

## What's next?

* Explore [other authentication methods](/traffic-policy/examples/add-authentication/) like OAuth, OIDC, JWT validation, or SAML that you can layer in using the same pattern.
* Use the action result variables and [CEL interpolation](/traffic-policy/how-it-works#cel-interpolation) to add specific error messages to your catch-all `custom-response` action.
* View your traffic in [Traffic Inspector](https://dashboard.ngrok.com/traffic-inspector) to see requests that failed to authenticate but should have—for example, maybe a specific IP address is missing from your `restrict-ips` allow list or a user who doesn't realize they're using an invalid JWT token.
