This is an automated email from the ASF dual-hosted git repository.

yuluo-yx pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git


The following commit(s) were added to refs/heads/master by this push:
     new d06aedfc2b [bugfix] Disable Digest authentication by default (#4436)
d06aedfc2b is described below

commit d06aedfc2bc522099d9cccff376205ddd19b1e97
Author: shown <[email protected]>
AuthorDate: Thu Oct 8 17:19:59 2026 +0800

    [bugfix] Disable Digest authentication by default (#4436)
---
 .github/workflows/backend-build-test.yml           |  15 +-
 .github/workflows/docker-compose-config-test.yml   |   6 +-
 e2e/README.md                                      |   3 +
 .../src/main/resources/application.yml             |   1 -
 home/docs/start/docker-compose-deploy.md           |   2 +
 home/docs/start/docker-deploy.md                   |  17 ++
 home/docs/start/quickstart.md                      |   2 +-
 .../current/help/tdengine_promql.md                |   2 +-
 .../current/start/docker-compose-deploy.md         |   2 +
 .../current/start/docker-deploy.md                 |  17 ++
 .../current/start/quickstart.md                    |   2 +-
 .../current/start/usecase/tdengine-practice.md     |   2 +-
 script/application.yml                             |   1 -
 script/ci/auth_contract_test.py                    | 198 +++++++++++++++++++++
 script/ci/check-quickstart-compose.sh              |  23 ++-
 script/docker-compose/README.md                    |  10 ++
 .../hertzbeat-mysql-iotdb/conf/application.yml     |   1 -
 .../hertzbeat-mysql-tdengine/conf/application.yml  |   1 -
 .../conf/application.yml                           |   1 -
 .../conf/application.yml                           |   1 -
 .../conf/application.yml                           |   1 -
 21 files changed, 292 insertions(+), 16 deletions(-)

diff --git a/.github/workflows/backend-build-test.yml 
b/.github/workflows/backend-build-test.yml
index 3220c5fde5..e0959d56c5 100644
--- a/.github/workflows/backend-build-test.yml
+++ b/.github/workflows/backend-build-test.yml
@@ -112,11 +112,20 @@ jobs:
           push: false
           tags: apache/hertzbeat:test
 
-      - name: Run E2E
+      - name: Start E2E environment
+        working-directory: e2e
         run: |
-          cd e2e
           docker compose version
-          docker compose up --exit-code-from testing --remove-orphans
+          docker compose up -d --wait hertzbeat checker
+
+      - name: Run authentication contract tests
+        env:
+          SERVER: http://localhost:1157
+        run: python3 script/ci/auth_contract_test.py
+
+      - name: Run API E2E tests
+        working-directory: e2e
+        run: docker compose up --exit-code-from testing --remove-orphans
 
       # upload application logs
       - name: Upload logs & API test reports
diff --git a/.github/workflows/docker-compose-config-test.yml 
b/.github/workflows/docker-compose-config-test.yml
index ed259afc39..f222c171a3 100644
--- a/.github/workflows/docker-compose-config-test.yml
+++ b/.github/workflows/docker-compose-config-test.yml
@@ -23,12 +23,16 @@ on:
     paths:
       - '.github/workflows/docker-compose-config-test.yml'
       - 'script/ci/check-quickstart-compose.sh'
+      - 'hertzbeat-startup/src/main/resources/application.yml'
+      - 'script/application.yml'
       - 'script/docker-compose/**'
   pull_request:
     branches: [ master, dev ]
     paths:
       - '.github/workflows/docker-compose-config-test.yml'
       - 'script/ci/check-quickstart-compose.sh'
+      - 'hertzbeat-startup/src/main/resources/application.yml'
+      - 'script/application.yml'
       - 'script/docker-compose/**'
 
 concurrency:
@@ -44,5 +48,5 @@ jobs:
     timeout-minutes: 5
     steps:
       - uses: actions/checkout@v4
-      - name: Validate quick-start listener bindings
+      - name: Validate quick-start configuration
         run: sh script/ci/check-quickstart-compose.sh
diff --git a/e2e/README.md b/e2e/README.md
index d372428010..bb5f753d89 100644
--- a/e2e/README.md
+++ b/e2e/README.md
@@ -13,6 +13,7 @@ Please add the corresponding e2e (aka end-to-end) test cases 
if you add or updat
     ```
 
 * Run the E2E tests via 
[api-testing](https://github.com/LinuxSuRen/api-testing)
+  * `script/ci/auth_contract_test.py` uses only the Python standard library to 
verify the default Basic/JWT behavior, including the absence of browser 
authentication challenges
   * The test cases run from top to bottom
   * You can add the necessary assertions there
   * Test data files are under `e2e/data/`
@@ -28,6 +29,8 @@ Please follow these steps if you want to run the E2E tests 
locally.
 * Change the directory to `e2e`, then run:
 
   ```bash
+  docker compose up -d --wait hertzbeat checker
+  SERVER=http://localhost:1157 python3 ../script/ci/auth_contract_test.py
   docker compose up --exit-code-from testing --remove-orphans
   ```
 
diff --git a/hertzbeat-startup/src/main/resources/application.yml 
b/hertzbeat-startup/src/main/resources/application.yml
index c6cd53d4e1..db22a026a5 100644
--- a/hertzbeat-startup/src/main/resources/application.yml
+++ b/hertzbeat-startup/src/main/resources/application.yml
@@ -84,7 +84,6 @@ springdoc:
 sureness:
   container: jakarta_servlet
   auths:
-    - digest
     - basic
     - jwt
   jwt:
diff --git a/home/docs/start/docker-compose-deploy.md 
b/home/docs/start/docker-compose-deploy.md
index e21b01c78b..b219eb9df5 100644
--- a/home/docs/start/docker-compose-deploy.md
+++ b/home/docs/start/docker-compose-deploy.md
@@ -73,6 +73,8 @@ Run the `docker compose version` command to check if you have 
a Docker Compose e
 
    This setting also opens `1158` for remote Collectors; `14317` (OTLP/gRPC) 
is controlled separately by `HERTZBEAT_OTLP_BIND_ADDRESS`. See the `README.md` 
of the deployment solution for details.
 
+   The supplied `conf/application.yml` enables Basic and JWT authentication by 
default, and the Web UI uses JWT. Digest is opt-in. If you add `digest` to 
`sureness.auths`, unauthenticated protected APIs return a `WWW-Authenticate: 
Digest` challenge and a browser may display its native username/password 
dialog. Restart the HertzBeat container after changing the configuration. See 
[Authentication modes](docker-deploy#authentication-modes) for examples and TLS 
guidance.
+
    :::
 
 **HAVE FUN**
diff --git a/home/docs/start/docker-deploy.md b/home/docs/start/docker-deploy.md
index bdeebc70e0..c0202d5534 100644
--- a/home/docs/start/docker-deploy.md
+++ b/home/docs/start/docker-deploy.md
@@ -56,6 +56,23 @@ It is necessary to have Docker environment in your 
environment. If not installed
 2. Start to explore HertzBeat  
    Access [http://ip:1157/](http://ip:1157/) using browser. You can explore 
HertzBeat with default account `admin/hertzbeat` now!
 
+### Authentication modes
+
+The default image enables Basic and JWT authentication. The Web UI signs in 
through the form endpoint and then uses JWT, while Basic remains available for 
API clients. Use TLS whenever credentials or tokens cross an untrusted network.
+
+Digest authentication is disabled by default. To change the enabled methods, 
download the complete 
[`application.yml`](https://github.com/apache/hertzbeat/raw/master/script/application.yml),
 edit its `sureness.auths` list, and mount the complete file as shown above. 
For example, enable Digest explicitly with:
+
+```yaml
+sureness:
+  container: jakarta_servlet
+  auths:
+    - digest
+    - basic
+    - jwt
+```
+
+When Digest is enabled, an unauthenticated request to a protected API returns 
a `WWW-Authenticate: Digest` challenge. Opening such an API in a browser may 
therefore display the browser's native username/password dialog; this is an 
HTTP authentication prompt, not a TLS or certificate error. To use JWT only, 
set `auths` to a single `jwt` entry. Restart the container after changing the 
file.
+
 ### Deploy HertzBeat Collector Cluster(Optional)
 
 :::note
diff --git a/home/docs/start/quickstart.md b/home/docs/start/quickstart.md
index d68cf330de..c26df67b5d 100644
--- a/home/docs/start/quickstart.md
+++ b/home/docs/start/quickstart.md
@@ -37,7 +37,7 @@ HertzBeat provides multiple installation options:
 
     ```docker run -d -p 1157:1157 -p 1158:1158 --name hertzbeat 
apache/hertzbeat```
 
-2. Access `http://localhost:1157` to start, default account: `admin/hertzbeat`
+2. Access `http://localhost:1157` to start, default account: 
`admin/hertzbeat`. The default image enables Basic and JWT authentication; the 
Web UI uses JWT. Digest authentication is opt-in because its browser challenge 
can open a native username/password dialog. See [Install HertzBeat via 
Docker](docker-deploy#authentication-modes) for configuration details.
 
 3. Deploy collector clusters(Optional)
 
diff --git 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/tdengine_promql.md
 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/tdengine_promql.md
index f4f8245737..dd43a8ab86 100644
--- 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/tdengine_promql.md
+++ 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/tdengine_promql.md
@@ -12,7 +12,7 @@ keywords: [ 开源监控系统,开源中间件监控, TDengine监控,TDengine-Pr
 
 1. 部署 TDengine;
 2. 部署 taosKeeper;注意⚠️安装 TDengine 官方安装包的同时会自动安装 taosKeeper
-   
详情请参考:[taosKeeper](https://docs.taosdata.com/3.4.1/reference/components/taoskeeper/);
+   
详情请参考:[taosKeeper](https://docs.tdengine.com/reference/components/taoskeeper/);
 3. 通过 prometheus 采集 TDengine taosKeeper 暴露的监控指标;
 
 ### 配置参数
diff --git 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/docker-compose-deploy.md
 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/docker-compose-deploy.md
index 021cb28003..6076d22ed0 100644
--- 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/docker-compose-deploy.md
+++ 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/docker-compose-deploy.md
@@ -71,6 +71,8 @@ sidebar_label: Docker Compose方式安装
 
    快速启动方案默认将所有宿主机端口绑定到 `127.0.0.1`,因此 Web 页面只能在运行 Docker 的本机访问。如需从其他主机访问,请在 
`.env` 中把 `HERTZBEAT_BIND_ADDRESS` 设置为其他主机可达的地址(建议通过 TLS 反向代理开放,而不是直接使用 
`0.0.0.0` 这类通配地址),然后执行 `docker compose config` 检查最终端口映射,再重新执行 `docker compose 
up -d`。该变量同时会开放 `1158` 供远程 Collector 连接;`14317`(OTLP/gRPC)由独立的 
`HERTZBEAT_OTLP_BIND_ADDRESS` 控制。详见部署方案目录下的 `README.md`。
 
+   随附的 `conf/application.yml` 默认启用 Basic 和 JWT 认证,Web UI 使用 JWT;Digest 
需要显式开启。如果在 `sureness.auths` 中加入 `digest`,未认证请求访问受保护接口时会收到 `WWW-Authenticate: 
Digest` 质询,浏览器可能弹出原生用户名密码框。修改配置后需要重启 HertzBeat 容器。示例和 TLS 建议参见 
[认证方式](docker-deploy#认证方式)。
+
    :::
 
 **HAVE FUN**
diff --git 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/docker-deploy.md 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/docker-deploy.md
index 061f4eb852..f1a7ae45cc 100644
--- 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/docker-deploy.md
+++ 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/docker-deploy.md
@@ -54,6 +54,23 @@ sidebar_label: Docker方式安装
 2. 开始探索 HertzBeat  
    浏览器访问 [http://ip:1157/](http://ip:1157/) 即可开始探索使用HertzBeat,默认账户密码 
admin/hertzbeat。
 
+### 认证方式
+
+默认镜像启用 Basic 和 JWT 认证。Web UI 通过表单接口登录,后续使用 JWT;Basic 保留给 API 
客户端使用。凭据或令牌经过不可信网络时,请使用 TLS。
+
+Digest 认证默认不启用。如需调整认证方式,请下载完整的 
[`application.yml`](https://github.com/apache/hertzbeat/raw/master/script/application.yml),修改其中的
 `sureness.auths` 列表,并按上面的命令挂载完整文件。例如,显式启用 Digest:
+
+```yaml
+sureness:
+  container: jakarta_servlet
+  auths:
+    - digest
+    - basic
+    - jwt
+```
+
+启用 Digest 后,未认证请求访问受保护接口时会收到 `WWW-Authenticate: Digest` 
质询,因此在浏览器中直接打开这类接口可能弹出浏览器原生用户名密码框;这是 HTTP 认证提示,不是 TLS 或证书错误。如只需 JWT,可将 `auths` 
设置为仅包含 `jwt`。修改文件后需要重启容器。
+
 ### 部署 HertzBeat Collector 集群(可选)
 
 :::note
diff --git 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/quickstart.md 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/quickstart.md
index ecb018ac8d..f071238283 100644
--- a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/quickstart.md
+++ b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/quickstart.md
@@ -41,7 +41,7 @@ HertzBeat 提供多种安装选项:
 
     ```docker run -d -p 1157:1157 -p 1158:1158 --name hertzbeat 
quay.io/tancloud/hertzbeat```
 
-2. 浏览器访问 `http://localhost:1157` 即可开始,默认账号密码 `admin/hertzbeat`
+2. 浏览器访问 `http://localhost:1157` 即可开始,默认账号密码 `admin/hertzbeat`。默认镜像启用 Basic 和 
JWT 认证,Web UI 使用 JWT。Digest 认证需要显式开启,因为其浏览器质询可能弹出原生用户名密码框。配置方法参见 [通过 Docker 
方式安装 HertzBeat](docker-deploy#认证方式)。
 
 3. 部署采集器集群(可选)
 
diff --git 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/usecase/tdengine-practice.md
 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/usecase/tdengine-practice.md
index 82be88c743..d364c5536f 100644
--- 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/usecase/tdengine-practice.md
+++ 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/start/usecase/tdengine-practice.md
@@ -31,7 +31,7 @@ Apache HertzBeat™ 一个拥有强大自定义监控能力,无需Agent的实
 ## 启用 TDengine 监控
 
 :::tip
-TDengine TSDB 集成了多种监控指标收集机制,并通过 taosKeeper 进行汇总,taosKeeper 是 TDengine TSDB 3.0 
版本监控指标的导出工具,通过简单的几项配置即可获取 TDengine TSDB 
的运行状态,参考:[https://docs.taosdata.com/3.4.1/reference/components/taoskeeper/](https://docs.taosdata.com/3.4.1/reference/components/taoskeeper/)
+TDengine TSDB 集成了多种监控指标收集机制,并通过 taosKeeper 进行汇总,taosKeeper 是 TDengine TSDB 3.0 
版本监控指标的导出工具,通过简单的几项配置即可获取 TDengine TSDB 
的运行状态,参考:[https://docs.tdengine.com/reference/components/taoskeeper/](https://docs.tdengine.com/reference/components/taoskeeper/)
 :::
 
 ## 监控 TDengine(PromQL)
diff --git a/script/application.yml b/script/application.yml
index c6cd53d4e1..db22a026a5 100644
--- a/script/application.yml
+++ b/script/application.yml
@@ -84,7 +84,6 @@ springdoc:
 sureness:
   container: jakarta_servlet
   auths:
-    - digest
     - basic
     - jwt
   jwt:
diff --git a/script/ci/auth_contract_test.py b/script/ci/auth_contract_test.py
new file mode 100644
index 0000000000..dd3bf97eb9
--- /dev/null
+++ b/script/ci/auth_contract_test.py
@@ -0,0 +1,198 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Verify the authentication contract of the default HertzBeat image."""
+
+import base64
+import json
+import os
+import sys
+import urllib.error
+import urllib.request
+
+
+SERVER = os.getenv("SERVER", "http://localhost:1157";).rstrip("/")
+USERNAME = os.getenv("AUTH_USERNAME", "admin")
+PASSWORD = os.getenv("AUTH_PASSWORD", "hertzbeat")
+TIMEOUT = float(os.getenv("AUTH_TEST_TIMEOUT", "10"))
+PROTECTED_RESOURCE = "/api/monitors?pageIndex=0&pageSize=1"
+
+
+def request(path, method="GET", payload=None, authorization=None):
+    headers = {"Accept": "application/json"}
+    body = None
+    if payload is not None:
+        headers["Content-Type"] = "application/json"
+        body = json.dumps(payload).encode("utf-8")
+    if authorization is not None:
+        headers["Authorization"] = authorization
+
+    req = urllib.request.Request(
+        f"{SERVER}{path}", data=body, headers=headers, method=method
+    )
+    try:
+        with urllib.request.urlopen(req, timeout=TIMEOUT) as response:
+            return response.status, response.headers, response.read()
+    except urllib.error.HTTPError as error:
+        return error.code, error.headers, error.read()
+
+
+def decode_json(body, context):
+    try:
+        return json.loads(body.decode("utf-8"))
+    except (UnicodeDecodeError, json.JSONDecodeError) as error:
+        raise AssertionError(f"{context} did not return valid JSON") from error
+
+
+def assert_success_response(status, body, context):
+    if status != 200:
+        raise AssertionError(f"{context} returned HTTP {status}; expected 200")
+    data = decode_json(body, context)
+    if data.get("code") != 0:
+        raise AssertionError(
+            f"{context} returned business code {data.get('code')}; expected 0"
+        )
+    return data.get("data")
+
+
+def assert_no_authentication_challenge(headers, context):
+    challenges = headers.get_all("WWW-Authenticate", [])
+    if challenges:
+        schemes = [challenge.split(maxsplit=1)[0] for challenge in challenges]
+        raise AssertionError(
+            f"{context} returned unexpected WWW-Authenticate schemes: 
{schemes}"
+        )
+
+
+def run_case(name, case):
+    try:
+        result = case()
+        print(f"PASS: {name}")
+        return result
+    except Exception as error:
+        print(f"FAIL: {name}: {error}", file=sys.stderr)
+        raise
+
+
+def anonymous_access_is_rejected_without_challenge():
+    status, headers, _ = request(PROTECTED_RESOURCE)
+    if status != 401:
+        raise AssertionError(f"Anonymous access returned HTTP {status}; 
expected 401")
+    assert_no_authentication_challenge(headers, "Anonymous access")
+
+
+def invalid_bearer_is_rejected_without_challenge(token):
+    parts = token.split(".")
+    if len(parts) != 3 or not parts[2]:
+        raise AssertionError("The login token is not a JWT")
+    replacement = "A" if parts[2][0] != "A" else "B"
+    parts[2] = replacement + parts[2][1:]
+    invalid_token = ".".join(parts)
+    status, headers, _ = request(
+        PROTECTED_RESOURCE, authorization=f"Bearer {invalid_token}"
+    )
+    if status != 401:
+        raise AssertionError(f"Invalid JWT returned HTTP {status}; expected 
401")
+    assert_no_authentication_challenge(headers, "Invalid JWT")
+
+
+def login():
+    status, _, body = request(
+        "/api/account/auth/form",
+        method="POST",
+        payload={"type": 0, "identifier": USERNAME, "credential": PASSWORD},
+    )
+    data = assert_success_response(status, body, "Form login")
+    if not isinstance(data, dict):
+        raise AssertionError("Form login response is missing the data object")
+    token = data.get("token")
+    refresh_token = data.get("refreshToken")
+    if not isinstance(token, str) or not token:
+        raise AssertionError("Form login response is missing token")
+    if not isinstance(refresh_token, str) or not refresh_token:
+        raise AssertionError("Form login response is missing refreshToken")
+    return token, refresh_token
+
+
+def bearer_access_succeeds(token):
+    status, _, body = request(
+        PROTECTED_RESOURCE, authorization=f"Bearer {token}"
+    )
+    assert_success_response(status, body, "JWT access")
+
+
+def basic_access_succeeds():
+    credentials = base64.b64encode(f"{USERNAME}:{PASSWORD}".encode("utf-8"))
+    status, _, body = request(
+        PROTECTED_RESOURCE,
+        authorization=f"Basic {credentials.decode('ascii')}",
+    )
+    assert_success_response(status, body, "Basic access")
+
+
+def refresh_token_succeeds(refresh_token):
+    status, _, body = request(
+        "/api/account/auth/refresh",
+        method="POST",
+        payload={"token": refresh_token},
+    )
+    data = assert_success_response(status, body, "Token refresh")
+    if (
+        not isinstance(data, dict)
+        or not data.get("token")
+        or not data.get("refreshToken")
+    ):
+        raise AssertionError("Token refresh response is missing token or 
refreshToken")
+
+    status, _, body = request(
+        PROTECTED_RESOURCE, authorization=f"Bearer {data['token']}"
+    )
+    assert_success_response(status, body, "Refreshed JWT access")
+
+
+def main():
+    print(f"HertzBeat authentication contract tests: {SERVER}")
+    run_case(
+        "anonymous access returns 401 without a browser authentication 
challenge",
+        anonymous_access_is_rejected_without_challenge,
+    )
+    token, refresh_token = run_case(
+        "form login returns access and refresh tokens", login
+    )
+    run_case(
+        "invalid JWT returns 401 without a browser authentication challenge",
+        lambda: invalid_bearer_is_rejected_without_challenge(token),
+    )
+    run_case(
+        "valid JWT can access a protected API", lambda: 
bearer_access_succeeds(token)
+    )
+    run_case(
+        "default Basic authentication can access a protected API",
+        basic_access_succeeds,
+    )
+    run_case(
+        "refresh token issues a usable JWT",
+        lambda: refresh_token_succeeds(refresh_token),
+    )
+    print("All authentication contract tests passed.")
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except (AssertionError, OSError, urllib.error.URLError):
+        sys.exit(1)
diff --git a/script/ci/check-quickstart-compose.sh 
b/script/ci/check-quickstart-compose.sh
index 24f0de50af..a3763066c3 100755
--- a/script/ci/check-quickstart-compose.sh
+++ b/script/ci/check-quickstart-compose.sh
@@ -62,6 +62,26 @@ assert_non_hertzbeat_bindings() {
     "$config_file" > /dev/null
 }
 
+assert_default_auths() {
+  application_file=$1
+  actual_auths=$(awk '
+    /^sureness:$/ { in_sureness = 1; next }
+    in_sureness && /^  auths:$/ { in_auths = 1; next }
+    in_auths && /^    - / { sub(/^    - /, ""); print; next }
+    in_auths { exit }
+  ' "$application_file")
+
+  if [ "$actual_auths" != "basic
+jwt" ]; then
+    echo "Unexpected default sureness.auths in ${application_file}:" >&2
+    echo "$actual_auths" >&2
+    return 1
+  fi
+}
+
+assert_default_auths 
"${repository_root}/hertzbeat-startup/src/main/resources/application.yml"
+assert_default_auths "${repository_root}/script/application.yml"
+
 for variant in \
   hertzbeat-mysql-iotdb \
   hertzbeat-mysql-tdengine \
@@ -70,6 +90,7 @@ for variant in \
   hertzbeat-postgresql-victoria-metrics
 do
   
compose_file="${repository_root}/script/docker-compose/${variant}/docker-compose.yaml"
+  assert_default_auths 
"${repository_root}/script/docker-compose/${variant}/conf/application.yml"
   default_config="${temporary_directory}/${variant}-default.json"
   override_config="${temporary_directory}/${variant}-override.json"
 
@@ -89,4 +110,4 @@ do
   assert_non_hertzbeat_bindings "$override_config" 127.0.0.1
 done
 
-echo "Quick-start Compose listener bindings are valid."
+echo "Quick-start Compose listener bindings and authentication defaults are 
valid."
diff --git a/script/docker-compose/README.md b/script/docker-compose/README.md
index 721c70550d..ae7b4d828b 100644
--- a/script/docker-compose/README.md
+++ b/script/docker-compose/README.md
@@ -28,6 +28,16 @@ only for trusted OTLP senders. Before using `0.0.0.0`, 
replace bundled/default
 credentials, apply firewall or security-group restrictions, and configure TLS.
 Run `docker compose config` to inspect the final bindings before startup.
 
+## Authentication defaults
+
+Every quick-start variant enables Basic and JWT authentication by default; the
+web UI uses JWT. Digest authentication is opt-in. If `digest` is added to
+`sureness.auths` in the variant's `conf/application.yml`, unauthenticated
+protected APIs return a `WWW-Authenticate: Digest` challenge and browsers may
+display a native username/password dialog. Restart the HertzBeat container
+after changing the file, and use TLS when credentials or tokens cross an
+untrusted network.
+
 
 - Use Postgresql + GreptimeDB as HertzBeat dependent storage -> 
[HertzBeat+PostgreSQL+GreptimeDB Solution](hertzbeat-postgresql-greptimedb)
 - Use Postgresql + VictoriaMetrics as HertzBeat dependent storage -> 
[HertzBeat+PostgreSQL+VictoriaMetrics 
Solution](hertzbeat-postgresql-victoria-metrics)
diff --git a/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml 
b/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
index 47be747361..091bec61e2 100644
--- a/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
+++ b/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
@@ -87,7 +87,6 @@ springdoc:
 sureness:
   container: jakarta_servlet
   auths:
-    - digest
     - basic
     - jwt
   jwt:
diff --git 
a/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml 
b/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
index 10c4df7d4e..6e762a6fab 100644
--- a/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
+++ b/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
@@ -87,7 +87,6 @@ springdoc:
 sureness:
   container: jakarta_servlet
   auths:
-    - digest
     - basic
     - jwt
   jwt:
diff --git 
a/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml 
b/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
index 5e11381cfb..cf940fca73 100644
--- 
a/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
+++ 
b/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
@@ -87,7 +87,6 @@ springdoc:
 sureness:
   container: jakarta_servlet
   auths:
-    - digest
     - basic
     - jwt
   jwt:
diff --git 
a/script/docker-compose/hertzbeat-postgresql-greptimedb/conf/application.yml 
b/script/docker-compose/hertzbeat-postgresql-greptimedb/conf/application.yml
index 4f4c476e86..5dc0e44b36 100644
--- a/script/docker-compose/hertzbeat-postgresql-greptimedb/conf/application.yml
+++ b/script/docker-compose/hertzbeat-postgresql-greptimedb/conf/application.yml
@@ -87,7 +87,6 @@ springdoc:
 sureness:
   container: jakarta_servlet
   auths:
-    - digest
     - basic
     - jwt
   jwt:
diff --git 
a/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
 
b/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
index 961848fba3..3bf98cd6df 100644
--- 
a/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
+++ 
b/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
@@ -87,7 +87,6 @@ springdoc:
 sureness:
   container: jakarta_servlet
   auths:
-    - digest
     - basic
     - jwt
   jwt:


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to