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

# Basic Auth Action

> Enforce HTTP Basic Auth on your endpoints.

export const ConfigField = ({title, type, cel = false, defaultValue = false, required = false, children}) => {
  const id = `config-${title.replace(/\.|\s|\*/g, "_")}`;
  return <div className="field pt-2.5 pb-5 my-2.5 border-gray-50 dark:border-gray-800/50 border-b" style={{
    scrollMarginTop: '120px'
  }} id={id}>
      <div className="flex font-mono group/param-head param-head break-all relative">
        <div className="flex-1 flex content-start py-0.5 mr-5">
          <div className="flex items-center flex-wrap gap-2">
            <div class="absolute -top-1.5">
              <a href={`#${id}`} className="-ml-10 flex items-center opacity-0 border-0 group-hover/param-head:opacity-100 py-2 [.expandable-content_&]:-ml-[2.1rem]" aria-label="Navigate to header">
                ​<div className="w-6 h-6 rounded-md flex items-center justify-center shadow-sm text-gray-400 dark:text-white/50 dark:bg-background-dark dark:brightness-[1.35] dark:ring-1 dark:hover::rightness-150 bg-white ring-1 ring-gray-400/30 dark:ring-gray-700/25 hover:ring-gray-400/60 dark:hover:ring-white/20">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="gray" height="12px" viewBox="0 0 576 512"><path d="M0 256C0 167.6 71.6 96 160 96h72c13.3 0 24 10.7 24 24s-10.7 24-24 24H160C98.1 144 48 194.1 48 256s50.1 112 112 112h72c13.3 0 24 10.7 24 24s-10.7 24-24 24H160C71.6 416 0 344.4 0 256zm576 0c0 88.4-71.6 160-160 160H344c-13.3 0-24-10.7-24-24s10.7-24 24-24h72c61.9 0 112-50.1 112-112s-50.1-112-112-112H344c-13.3 0-24-10.7-24-24s10.7-24 24-24h72c88.4 0 160 71.6 160 160zM184 232H392c13.3 0 24 10.7 24 24s-10.7 24-24 24H184c-13.3 0-24-10.7-24-24s10.7-24 24-24z"></path></svg>
                </div>
              </a>
            </div>
            <div className="font-semibold text-primary dark:text-primary-light overflow-wrap-anywhere">{title}</div>
            <div className="inline items-center gap-2 text-xs font-medium [&_div]:inline [&_div]:mr-2 [&_div]:leading-5 [&_a]:inline [&_a]:mr-2 [&_a]:leading-5">
              {type && <div className="flex items-center px-2 py-0.5 rounded-md bg-gray-100/50 dark:bg-white/5 break-all">
                <span className="text-gray-600 dark:text-gray-200 !font-medium">{type}</span>
              </div>}
              {defaultValue && <div className="flex items-center px-2 py-0.5 rounded-md bg-gray-100/50 dark:bg-white/5 break-all">
                  <span class="text-gray-400 dark:text-gray-500">default:</span>
                  <span className="text-gray-600 dark:text-gray-200 !font-medium">{defaultValue}</span>
                </div>}
              {required && <div className="px-2 py-0.5 rounded-md bg-red-100/50 dark:bg-red-400/10 whitespace-nowrap">
                <span className="text-red-600 dark:text-red-300 !font-medium">Required</span>
              </div>}
              {cel && <a className="px-2 py-0.5 rounded-md !border-none bg-blue-100/50 dark:bg-blue-400/10 whitespace-nowrap" href="/traffic-policy/concepts/cel-interpolation">
                <span className="text-blue-600 dark:text-blue-300 !font-medium">Supports CEL</span>
              </a>}
            </div>
          </div>
        </div>
      </div>
      <div className="mt-4 prose-sm prose-gray dark:prose-invert [&_.prose>p:first-child]:mt-0 [&_.prose>p:last-child]:mb-0">
        {children}
      </div>
    </div>;
};

The Basic Auth action enables you to enforce HTTP Basic Auth on your endpoints. Requests with a valid username and password will be sent to
your upstream service, all others will be rejected with a `401 Unauthorized` response.

## Configuration reference

This is the [Traffic Policy](/traffic-policy/) configuration
reference for this action.

### Supported phases

`on_http_request`

### Type

`basic-auth`

### Configuration fields

<ConfigField title="credentials" type="array of strings" required={true} cel={true}>
  <p>A list of up to 10 allowed <code>username:password</code> credential pairs.</p>
  <p>Password must be at least <code>8</code> characters and no more than <code>128</code> characters.</p>
</ConfigField>

<ConfigField title="realm" type="string" required={false} defaultValue="ngrok">
  <p>The HTTP realm of the request as per <a href="https://datatracker.ietf.org/doc/html/rfc7235">RFC 7235</a>.</p>
</ConfigField>

<ConfigField title="enforce" type="bool" required={false} defaultValue="true">
  If <code>false</code>, continue to the next action even if basic authentication failed.

  This is useful for handling fall-through, debugging, and testing purposes.
</ConfigField>

## Behavior

The **basic-auth** action enforces HTTP Basic Authentication on incoming requests, as specified
in [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235). When a request is received, the action
verifies the request by validating against a known set of `user:password` credentials. If the
verification is successful, the action allows the request to continue through the action chain and
finally to your application; if verification fails, the request will be terminated with a
`401 Unauthorized` response.

### Additional restrictions

You can specify up to 10 `username:password` pairs. The password must be at least
8 characters and no more than 128 characters. Including multiple colons in the `username:password`
pair will result in the first colon being treated as the delimiter between the username and password.
Realm cannot exceed 128 characters, and cannot contain non-ASCII characters.

### Verification process

* **HTTP Authentication**: The action validates incoming HTTP requests to confirm they contain the required `Authorization` header, in the form of `Authorization: Basic <credentials>`, where `<credentials>` is the Base64 encoding of username and password joined by a single colon `:`.
* **Request Handling**: If the authentication is successful, the request is forwarded to the next action. If the authentication fails, it will return to user a `401` response, which will prompt the user to provide a correct set of credentials.
* **Configurable Enforcement**: By default, authentication failures result in 401s. However, setting `enforce: false` allows unauthenticated requests to proceed, while logging the authentication result. This option is for debugging and testing.

### Secret handling and encryption

All secrets used for basic authentication are encrypted at config validation. When ngrok processes a request, the secret is decrypted.

### Using CEL in credentials

You can use CEL interpolation in credentials, but the expression must stay properly scoped. A CEL expression can:

* produce the entire credential,
* produce the whole username or password, or
* produce part of the username or password.

If the expression does not produce the entire credential, you must include the `:` separator literally, and the expression itself cannot introduce another colon.

#### Valid patterns

* `${CEL_EXPRESSION}` - Entire credential is dynamic
* `${CEL_EXPRESSION}:password` - Dynamic username, literal password
* `${CEL_EXPRESSION}:${CEL_EXPRESSION}` - Both username and password are dynamic
* `user-prefix${CEL_EXPRESSION}:password` - Part of the username is dynamic, literal password

#### Invalid patterns

* `${CEL_EXPRESSION}password` - Missing colon separator between username and password
* `user-prefix${CEL_EXPRESSION}password-suffix` - Missing colon separator between username and password

### Non-terminating action

This is a **Non-terminating action**. It does not return a response, and will allow Traffic Policy processing to continue to the next Action in the chain. All **Cloud Endpoint** Traffic Policies must end with a terminating action. This requirement does not apply to **Agent Endpoints**.

## Examples

### Basic example

The following [Traffic Policy](/traffic-policy/)
configuration is an example configuration of the `basic-auth` action.

#### Example Traffic Policy document

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
      - type: "basic-auth"
        config:
          realm: "sample-realm"
          credentials:
            - "user:password1"
            - "admin:password2"
          enforce: true
      - type: "custom-response"
        config:
          status_code: 200
          headers:
            content-type: "text/plain"
          body: "Successfully Authenticated!"
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "basic-auth",
            "config": {
              "realm": "sample-realm",
              "credentials": [
                "user:password1",
                "admin:password2"
              ],
              "enforce": true
            }
          },
          {
            "type": "custom-response",
            "config": {
              "status_code": 200,
              "headers": {
                "content-type": "text/plain"
              },
              "body": "Successfully Authenticated!"
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

### Example request

First, base64 encode the `username:password` pair.
`user:password1` becomes `dXNlcjpwYXNzd29yZDE=`

```bash theme={null}
$ curl --request GET \
  --url http://example-api.ngrok.app/ \
  --header 'Authorization: Basic dXNlcjpwYXNzd29yZDE=`'
```

```http theme={null}
HTTP/2 200 OK
content-type: text/html
Successfully Authenticated!
...
```

In this example, a request is sent to the API with a valid set of credentials in
the `Authorization` header with the `Basic` prefix and getting back a `200 OK`
response.

You can try it without the header, and you will receive a `401 Unauthorized` prompt
instead.

## Action result variables

The following variables are made available for use in subsequent expressions and
CEL interpolations after the action has run. Variable values will only apply
to the last action execution, results are not concatenated.

<ConfigField title="actions.ngrok.basic_auth.credentials.presented" type="bool" required={false}>
  <p>Whether there were Basic Auth credentials presented in the Authorization header.</p>
</ConfigField>

<ConfigField title="actions.ngrok.basic_auth.credentials.username" type="string" required={false}>
  <p>The username of the credentials presented.</p>
</ConfigField>

<ConfigField title="actions.ngrok.basic_auth.credentials.authorized" type="bool" required={false}>
  <p>Whether the presented basic auth credentials were authorized for this request.</p>
</ConfigField>
