🐛 [Bug Report] Native browser HTTP Basic Auth dialog on login page
- 主要言語
- Python
- スター
- 22.1k
- フォーク
- 5.3k
- PR マージ指標
- PR 指標を取得中
説明
### Topic
Self-hosted UI login shows the browser's native gray "Sign in" (HTTP Basic Auth) dialog before the in-app login screen. Dismissing with **Cancel** allows the normal HTML login UI to appear.
### Relevant information
*Environment*
- Airbyte: **2.1.0** (self-hosted, `abctl local install` on Kubernetes via kind)
- Deployment: EC2 + ALB → nginx ingress (`abctl`) → `airbyte-server`
- Auth: `global.auth.enabled: true` (instance admin / simple auth — **not** nginx ingress basic auth)
- Ingress: chart/nginx **HTTP Basic Auth annotations removed** (aligned with [abctl PR #56](https://github.com/airbytehq/abctl/pull/56) and [#41634](https://github.com/airbytehq/airbyte/issues/41634))
- Browser: **Island** Version 1.91.20 Chromium: 148.0.7778.168 (Official Build) (arm64)
---
*Summary*
On first load of `/login`, the webapp runs a session probe (`POST /api/v1/users/get` with `userId: 00000000-0000-0000-0000-000000000000`) using **credentialed** `fetch` (`credentials: "include"`). When no session cookie is present, the server responds with **401** and a JSON body — but also sends:
```http
WWW-Authenticate: Basic charset="UTF-8", realm="airbyte-server", Bearer resource_metadata="..."
```
Browsers may interpret this as an HTTP Basic challenge and show the **native OS/browser auth dialog** (gray "Sign in"), which is distinct from Airbyte's HTML login. **Cancel** on that dialog is a workable workaround; the app then continues to the normal login UI.
This appears to be a mismatch between **cookie/HTML simple auth** (product intent) and **Micronaut security advertising `WWW-Authenticate: Basic`** on API 401s — not leftover nginx ingress basic auth.
---
*Step 1 — Static routes do not challenge Basic*
```bash
curl -sI 'https:///'
# HTTP/2 200 — no WWW-Authenticate
curl -sI 'https:///api/v1/health'
# HTTP/2 200 — no WWW-Authenticate
```
So the ALB/ingress path for `/` and health does **not** explain the browser dialog.
---
*Step 2 — Session probe API returns 401 + `WWW-Authenticate: Basic`*
Same request the webapp makes on login (no session cookie):
```bash
curl -s -D - -o /dev/null -X POST 'https:///api/v1/users/get' \
-H 'content-type: application/json' \
--data-raw '{"userId":"00000000-0000-0000-0000-000000000000"}'
```
Observed response headers:
```http
HTTP/2 401
content-type: application/json
www-authenticate: Basic charset="UTF-8", realm="airbyte-server", Bearer resource_metadata="http:///.well-known/oauth-protected-resource/api/v1/users/get"
```
Body (abbreviated):
```json
{"message":"Unauthorized","_links":{"self":{"href":"/api/v1/users/get","templated":false}},...}
```
---
*Step 3 — Browser behavior (DevTools)*
On `/login`, Network tab shows:
- **Request:** `POST /api/v1/users/get` (XHR/fetch, `credentials: include`, `X-Airbyte-Analytic-Source: webapp`)
- **Response:** `401` + `www-authenticate: Basic ... realm="airbyte-server"`
The native Basic Auth dialog is consistent with **credentialed fetch + 401 + `WWW-Authenticate: Basic`** (standard browser behavior; JS cannot suppress the dialog programmatically).
---
*Step 4 — Client code path (airbyte-platform)*
Startup session check uses credentialed API calls, e.g. `useGetDefaultUserAsync()` → `POST /api/v1/users/get`. The generated client uses `fetch` with `credentials: "include"` when `includeCredentials` is set (same pattern as obfuscated production bundle: `fetch(..., { credentials: "include" })`).
Server side, `UserApiController` is secured (`@Secured(IS_AUTHENTICATED)`), so unauthenticated probes correctly get 401 — but the **Basic** challenge header on that response is what triggers the browser dialog.
---
*Expected behavior*
- Login page shows **only** the in-app HTML login (per [#41634](https://github.com/airbytehq/airbyte/issues/41634) / removal of nginx basic auth).
- Unauthenticated `POST /api/v1/users/get` during session probe should return **401 JSON only**, without advertising **HTTP Basic** to the browser.
*Actual behavior*
- Native browser HTTP Basic Auth dialog may appear on `/login`.
- User must click **Cancel** to reach the normal login UI.
---
*Workaround*
Click **Cancel** on the browser Basic Auth dialog, then use HTML login.
---
*Related issues*
- [#45197](https://github.com/airbytehq/airbyte/issues/45197) — same `POST /api/v1/users/get` 401 on startup (network/proxy focus; no browser Basic dialog called out)
- [#44198](https://github.com/airbytehq/airbyte/issues/44198) — `users/get` on page load behind reverse proxy
- [#41634](https://github.com/airbytehq/airbyte/issues/41634) — K8s/abctl should use in-app login, not HTTP Basic at the edge
- [abctl#56](https://github.com/airbytehq/abctl/pull/56) — removed nginx ingress basic auth
---
Initial request:
```bash
curl 'https://mycompany.com/' \
-H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \
-H 'accept-language: en-US,en;q=0.9' \
-H 'cache-control: no-cache' \
-b 'ajs_anonymous_id=REDACTED; ajs_user_id=REDACTED' \
-H 'pragma: no-cache' \
-H 'priority: u=0, i' \
-H 'sec-ch-ua: "Chromium";v="148", "Island";v="148", "Not/A)Brand";v="99"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
-H 'sec-fetch-dest: document' \
-H 'sec-fetch-mode: navigate' \
-H 'sec-fetch-site: none' \
-H 'sec-fetch-user: ?1' \
-H 'upgrade-insecure-requests: 1' \
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36'
```
Response:
```bash
HTTP/2 200
date: Tue, 19 May 2026 14:04:34 GMT
content-security-policy: script-src * 'unsafe-inline'; worker-src 'self' blob:;
last-modified: Tue, 19 May 2026 14:04:34 GMT
cache-control: no-cache, no-store, must-revalidate, max-age=0
```
```html
...
```
The SPA from that page calls:
```bash
curl 'https://mycompany.com/api/v1/users/get' \
-H 'accept: */*' \
-H 'accept-language: en-US,en;q=0.9' \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-b 'ajs_anonymous_id=REDACTED; ajs_user_id=REDACTED' \
-H 'origin: https://mycompany.com' \
-H 'pragma: no-cache' \
-H 'priority: u=1, i' \
-H 'referer: https://mycompany.com/' \
-H 'sec-ch-ua: "Chromium";v="148", "Island";v="148", "Not/A)Brand";v="99"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
-H 'sec-fetch-dest: empty' \
-H 'sec-fetch-mode: cors' \
-H 'sec-fetch-site: same-origin' \
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36' \
-H 'x-airbyte-analytic-source: webapp' \
--data-raw '{"userId":"00000000-0000-0000-0000-000000000000"}'
```
Response:
```bash
HTTP/2 401
date: Tue, 19 May 2026 14:08:17 GMT
content-type: application/json
content-length: 170
www-authenticate: Basic charset="UTF-8", realm="airbyte-server", Bearer resource_metadata="http://mycompany.com/.well-known/oauth-protected-resource/api/v1/users/get"
access-control-allow-origin: https://mycompany.com
vary: Origin
access-control-allow-credentials: true
```
```bash
{"message":"Unauthorized","_links":{"self":{"href":"/api/v1/users/get","templated":false}},"_embedded":{"errors":[{"message":"Unauthorized","_links":{},"_embedded":{}}]}}%
```
---
*Helm / `abctl` values (redacted)*
Installed with **`abctl local install`** (chart **2.1.0**). Instance admin credentials are supplied via a separate Kubernetes `Secret` passed as `--secret` (not in `values.yaml`).
```yaml
# /opt/airbyte/values.yaml (written at bootstrap; secrets redacted)
global:
edition: community
airbyteUrl: "https://"
auth:
enabled: true
database:
type: external
host: ""
port: 5432
database: "db-airbyte"
user: ""
password: ""
externalDatabase:
host: ""
port: 5432
database: "db-airbyte"
user: ""
password: ""
jdbcUrl: ""
postgresql:
enabled: false
ingress:
enabled: true
className: nginx
hosts:
- host: ""
paths:
- path: /
pathType: Prefix
backend: server
# No nginx.ingress.kubernetes.io/auth-type / auth-secret annotations
temporal:
extraEnv:
- name: SKIP_DB_CREATE
value: "true"
webapp:
service:
type: ClusterIP
server:
resources:
requests: { cpu: "500m", memory: "2Gi" }
limits: { cpu: "2", memory: "4Gi" }
worker:
resources:
requests: { cpu: "1", memory: "4Gi" }
limits: { cpu: "3", memory: "10Gi" }
jobs:
resources:
requests: { cpu: "", memory: "" }
limits: { cpu: "", memory: "" }
```
```yaml
# airbyte-auth-secret.yaml (passed to abctl as --secret; values redacted)
apiVersion: v1
kind: Secret
metadata:
name: airbyte-auth-secrets
type: Opaque
stringData:
instance-admin-password: ""
instance-admin-client-id: ""
instance-admin-client-secret: ""
```
```bash
abctl local install \
--port 8000 \
--no-browser \
--values /opt/airbyte/values.yaml \
--secret /opt/airbyte/airbyte-auth-secret..yaml \
--chart-version 2.1.0
```
Not configured (relevant to this bug): `micronaut.security.basic-auth.enabled`, ingress HTTP Basic Auth, or `global.auth` modes other than enabled simple/instance admin.
Thanks!
---
**Internal Tracking:** https://github.com/airbytehq/oncall/issues/12649
コントリビューションガイド
評価
この issue はまだ評価されていません。