Resolving Swagger 403, ArgoCD Dashboard, and CORS Issues
2026-03-11 | Resolving Swagger 403, ArgoCD Dashboard, and CORS Issues
1. Swagger 403 → OAuth Login Redirect#
Problem#
- Accessing
swagger.dev.goormgb.spaceshows a 403 Forbidden page - No redirect to the login page
Root Cause#
- Browser has a stale cookie (expired
_oauth2_proxycookie) - OAuth2 Proxy validates the cookie, finds it invalid → returns 403
- Normal flow: no cookie → 302 redirect → login
[Normal flow - no cookie]
User → OAuth2 Proxy → no cookie → 302 → Google login
[Problem - expired cookie]
User → OAuth2 Proxy → cookie present (expired) → 403 Forbidden
↑ stops here!
Fix: EnvoyFilter to convert 403→302 redirect#
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: swagger-403-redirect
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: envoy.filters.http.router
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inlineCode: |
function envoy_on_response(response_handle)
local host = response_handle:headers():get(":authority") or ""
local status = response_handle:headers():get(":status")
-- only handle 403 responses on the swagger domain
if string.find(host, "swagger") and status == "403" then
local path = response_handle:headers():get("x-original-uri") or "/"
local redirect_url = "/oauth2/start?rd=" .. path
-- convert to 302 redirect
response_handle:headers():replace(":status", "302")
response_handle:headers():add("location", redirect_url)
response_handle:headers():add("cache-control", "no-cache, no-store")
end
end
Key Points#
- envoy_on_response: intercepts at the response phase
- swagger domain only: no impact on other services
- 403 → 302 conversion +
/oauth2/startredirect - OAuth2 Proxy restarts the login process
2. CORS Errors Causing Frontend Blank Page#
Problem#
- CORS errors when the frontend makes API calls
- Only errors visible in the browser console; the page goes blank
Root Cause#
- The backend does not include CORS headers in 400/500 error responses
[Successful 200 response]
Access-Control-Allow-Origin: https://dev.goormgb.space ✓
→ Frontend can read the response body
[Error 500 response]
Access-Control-Allow-Origin: (absent) ✗
→ Browser blocks the response → frontend cannot determine the error cause
→ Error handling fails → blank page
Why CORS headers are needed even on error responses#
- Browser security policy: All responses require CORS headers when origins differ
- Error handling: Without CORS headers,
response.json()itself fails - UX improvement: Error messages can be surfaced to the user
Fix (forwarded to backend team)#
// Spring Boot - include CORS headers in error responses too
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://dev.goormgb.space")
.allowedMethods("*")
.allowCredentials(true);
}
}
// Or add headers to all exception responses via @ControllerAdvice
3. /auth/token/refresh 404 Error#
Problem#
- Frontend calls
/auth/token/refreshand receives 404
Root Cause: Path Mismatch#
| Side | Path |
|---|---|
| Frontend call | /auth/token/refresh |
| API Gateway routing | Path=/auth/** → Auth-Guard |
| Auth-Guard actual path | /token/refresh (no class-level @RequestMapping) |
Frontend: /auth/token/refresh
↓
API Gateway: matches /auth/** → forwards to Auth-Guard
↓
Auth-Guard: receives /auth/token/refresh
↓
404! (only /token/refresh actually exists)
Fix (forwarded to backend team)#
Option 1: Add StripPrefix filter (recommended)
routes:
- id: auth-guard
uri: ${AUTH_GUARD_URL}
predicates:
- Path=/auth/**
filters:
- StripPrefix=1 # /auth/token/refresh → /token/refresh
Option 2: Add @RequestMapping to the Controller
@RestController
@RequestMapping("/auth") // add this
public class AuthController {
4. ArgoCD Dashboard Improvements#
Changes#
Dashboard split
argocd-app-deployments.json- service apps (dev-*)argocd-infra-deployments.json- infra (Istio, Monitoring, etc.)
Unhealthy query fix
- Before:
health_status=~"Degraded|Progressing|Unknown"(counted Progressing as Unhealthy) - After:
health_status="Degraded"+OR on() vector(0)(shows 0 when no results)
- Before:
Log section added (same in both dashboards)
- Reconciliation count (Loki timeseries)
- Error logs (Loki logs)
- Webhook received logs
- Sync completed logs
Default time range changed
now-24h→now-30m- Fixes Loki query timeout issues
Header condensed to one line (removes scrollbar)
File Changes#
Created#
dev/root/infra/security/swagger-403-redirect.yaml
Modified#
common-charts/.../argocd-app-deployments.jsoncommon-charts/.../argocd-infra-deployments.jsondev/root/kustomization.yaml(registers swagger-403-redirect)
5. Helm Chart Dependency Management#
Problem#
Error: An error occurred while checking for chart dependencies.
You may need to run `helm dependency build` to fetch missing dependencies:
found in Chart.yaml, but missing in charts/ directory: base
ArgoCD cannot find dependencies when running helm template.
Root Cause#
- Dependencies are defined in the Helm chart’s
Chart.yaml - Running
helm dependency builddownloads them to thecharts/directory - If
charts/is in.gitignoreor not committed, ArgoCD cannot use them
Fix: Periodic dependency updates#
# 1. Add Helm repos (one-time)
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo add calico https://docs.tigera.io/calico/charts
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
# 2. Build dependencies
helm dependency build common-charts/infra/istio/base
helm dependency build common-charts/infra/calico
helm dependency build common-charts/infra/monitoring/loki
# 3. Commit the charts/ directory
git add common-charts/**/charts/
git commit -m "chore(helm): update chart dependencies"
git push
Why this needs to be done periodically#
- Version upgrades: when upstream chart versions change,
Chart.yamlmust be updated and rebuilt - Chart.lock mismatch: rebuild when lock files differ between local and remote
- Cache issues: when the ArgoCD repo-server cache is stale
Automation (TODO)#
- Run
helm dependency buildautomatically in CI/CD - Or use
helm.skipCrds: true+ pre-sync hook in the ArgoCD Application
6. EnvoyFilter Dynamic Metadata Issue#
Problem#
- Accessing the
:authorityheader inenvoy_on_responsereturns nil
Root Cause#
:authorityis a request header and cannot be accessed during the response phase- To pass request information into the response phase in an Envoy Lua filter, dynamic metadata must be used
Fix#
-- Request phase: save to metadata
function envoy_on_request(request_handle)
local host = request_handle:headers():get(":authority") or ""
local path = request_handle:headers():get(":path") or "/"
if string.find(host, "swagger") then
request_handle:streamInfo():dynamicMetadata():set("swagger_filter", "is_swagger", "true")
request_handle:streamInfo():dynamicMetadata():set("swagger_filter", "original_path", path)
end
end
-- Response phase: read from metadata
function envoy_on_response(response_handle)
local metadata = response_handle:streamInfo():dynamicMetadata():get("swagger_filter")
if metadata and metadata["is_swagger"] == "true" then
-- processing logic
end
end
7. Istio IngressGateway Routing Sync Issue#
Problem#
- Routing changes to VirtualService/EnvoyFilter are not reflected immediately
- 404 errors occur even when
istioctl proxy-statusshows SYNCED
Root Cause#
- Config push delay between Istiod and IngressGateway
- Potential conflicts when multiple VirtualServices reference the same host
Fix#
# Restart IngressGateway (most reliable)
kubectl rollout restart deployment istio-ingressgateway -n istio-system
# Or restart Istiod (re-sends config to all proxies)
kubectl rollout restart deployment istiod -n istio-system
Prevention#
- Clean up unnecessary VirtualServices (e.g.
faro-receiver) - Remove VirtualServices referencing deleted services
Commits#
fix(grafana): standardize ArgoCD dashboard structure and fix Unhealthy query
feat(istio): add swagger 403→login redirect EnvoyFilter
fix(istio): use dynamic metadata for EnvoyFilter cross-phase header access
chore(helm): add chart dependencies for istio, calico, loki