NGINX Basic Auth Breaks Wallet API (401s)
Why basic auth on /* blocks Bearer token API calls, and the robust two-ingress solution.
The Problem
I added NGINX basic auth to protect my wallet UI, but now the wallet is broken and API calls return 401. What went wrong?
The Answer
The wallet UI makes browser-side requests to /api/validator/* usingAuthorization: Bearer <JWT>.
If you enable NGINX basic auth on /*, NGINX will challenge those API calls too, effectively rejecting the Bearer token flow and returning 401.
Quick Mental Model
- UI pages (HTML/JS) can be protected with basic auth
- API calls from the browser must reach the validator backend using Bearer tokens
- If basic auth sits "in front" of both, your browser will never successfully call the API without also satisfying basic auth
Symptoms You'll See
- Wallet UI loads (sometimes), but actions fail
- Browser dev tools show requests like
GET /api/validator/v0/...returning401 - NGINX may return
WWW-Authenticate: Basic realm="..."even though the request includesAuthorization: Bearer ...
Why It Happens
Your ingress is applying basic auth at the host/root level, so it intercepts all paths including /api/validator/*.
NGINX basic auth and Bearer auth are not additive here: the basic auth challenge blocks the request before your app can validate the Bearer token.
The Tempting "Wrong Fix": Configuration Snippets
You might try to bypass basic auth for /api/validator usingnginx.ingress.kubernetes.io/configuration-snippet.
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($uri ~ "^/api/validator") {
set $auth_basic off;
}The Right Fix: Split UI and API Ingress Rules
Create two Ingress resources for the same host:
- Ingress A:
path: /with basic auth → routes towallet-web-ui - Ingress B:
path: /api/validatorwithout basic auth → routes tovalidator-app
Because ingress controllers prioritize the most specific / longest matching path,/api/validator will win over /.
Ingress 1 — UI (Protected)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: validator-ingress-ui
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: validator-basic-auth
# optional:
# nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
spec:
rules:
- host: wallet.validator.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wallet-web-ui
port:
number: 80Ingress 2 — API (NOT Protected by Basic Auth)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: validator-ingress-api
spec:
rules:
- host: wallet.validator.example.com
http:
paths:
- path: /api/validator
pathType: Prefix
backend:
service:
name: validator-app
port:
number: 5003Verify It Works
1) UI should still be protected:
curl -I https://wallet.validator.example.com/
# Expect: 401 + WWW-Authenticate: Basic ...2) API path should NOT challenge with basic auth:
curl -I https://wallet.validator.example.com/api/validator/v0/user
# Expect: NOT a Basic challenge
# You may still get 401 if you didn't provide a Bearer token,
# but it should be from the app/auth flow, not basic auth.3) In browser dev tools, confirm /api/validator/* requests are no longer blocked by basic auth.
Key Takeaways
- Never put basic auth on
/api/validator/*— those endpoints are meant to use Bearer tokens - Prefer "two-ingress, same host" over controller snippets — it's portable and predictable
- Rely on path specificity:
/api/validatorshould override/when both exist - You can still share the same TLS certificate/secret across both Ingress objects

