Drafted by ChatGPT
Describe the bug
When using OIDC auth, Radar can get stuck in a login loop during initial frontend boot.
A single browser tab repeatedly initiates /auth/login from the JavaScript bundle after protected /api/* requests return 401. Each /auth/login generates a new radar_oidc_state cookie. Because that cookie changes on each redirect/reload, callbacks from earlier OIDC redirects can fail or be canceled.
Eventually one callback may “win” and the app starts working, but the initial login flow is flaky and noisy.
To reproduce
Steps to reproduce the behavior:
- Run Radar
1.7.6 with OIDC enabled.
- Use a normal browser session with no valid Radar session.
- Open Radar, for example
/traffic.
- Open browser DevTools with Network logs preserved.
- Observe protected API calls such as
/api/connection, /api/capabilities, /api/namespaces, /api/portforwards, etc. returning 401.
- Observe
/auth/login being initiated by the JS bundle.
- Observe the
radar_oidc_state cookie changing repeatedly across reloads/redirects.
- Observe some callbacks failing with
400 or 500, or token exchange cancellation.
- Eventually, after one callback succeeds and the app settles, the same API calls return
200.
Expected behavior
Radar should start at most one OIDC login flow during frontend boot.
Repeated protected API 401s from the same SPA load should not independently initiate multiple /auth/login navigations or repeatedly overwrite radar_oidc_state.
After a successful OIDC callback, the browser should land back in the app with a valid session, and API calls should return 200 without repeated login redirects.
Screenshots
Not included.
Diagnostics (optional)
- Radar version:
ghcr.io/skyhook-io/radar:1.7.6
- Kubernetes:
v1.35.4+k3s1
- Auth mode: OIDC
- OIDC provider: Authentik
- Browser: Firefox
- Radar replicas:
1
RADAR_AUTH_SECRET: configured and stable
- Browser tabs: only one Radar tab open
Logs
2026/07/04 18:12:01 [oidc] Using IdP-provided session ID (sid claim present)
2026/07/04 18:12:01 [oidc] User bitbloxhub@local.invalid authenticated (groups: [])
2026/07/04 18:12:02 "GET http://radar.k3s-podman-testing.localhost:4962/api/connection HTTP/1.1" ... - 401 54B
2026/07/04 18:12:02 "GET http://radar.k3s-podman-testing.localhost:4962/auth/login HTTP/1.1" ... - 302 314B
2026/07/04 18:12:03 [oidc] Using IdP-provided session ID (sid claim present)
2026/07/04 18:12:03 "GET http://radar.k3s-podman-testing.localhost:4962/auth/callback?code=...&state=..." ... - 302 24B
2026/07/04 18:12:03 [oidc] User bitbloxhub@local.invalid authenticated (groups: [])
2026/07/04 18:12:03 "GET http://radar.k3s-podman-testing.localhost:4962/api/connection HTTP/1.1" ... - 401 54B
2026/07/04 18:13:23 "GET http://radar.k3s-podman-testing.localhost:4962/auth/callback?code=...&state=..." ... - 400 44B
2026/07/04 18:13:29 [oidc] Token exchange failed: Post "http://authentik.k3s-podman-testing.localhost:4962/application/o/token/": context canceled
2026/07/04 18:13:29 "GET http://radar.k3s-podman-testing.localhost:4962/auth/callback?code=...&state=..." ... - 500 22B
# Eventually one callback succeeds and the app starts working:
2026/07/04 18:14:13 [oidc] Using IdP-provided session ID (sid claim present)
2026/07/04 18:14:13 "GET http://radar.k3s-podman-testing.localhost:4962/auth/callback?code=...&state=..." ... - 302 24B
2026/07/04 18:14:13 [oidc] User bitbloxhub@local.invalid authenticated (groups: [])
2026/07/04 18:14:15 "GET http://radar.k3s-podman-testing.localhost:4962/api/connection HTTP/1.1" ... - 200 234B
2026/07/04 18:14:15 "GET http://radar.k3s-podman-testing.localhost:4962/api/auth/me HTTP/1.1" ... - 200 91B
2026/07/04 18:14:20 "GET http://radar.k3s-podman-testing.localhost:4962/api/traffic/flows?since=5m HTTP/1.1" ... - 200 474439B
2026/07/04 18:14:20 [hubble] Retrieved 1000 flows
Deployment details:
replicas: 1
args:
- --auth-cookie-ttl=4h
- --auth-user-header=X-Forwarded-User
- --auth-groups-header=X-Forwarded-Groups
- --auth-oidc-issuer=http://authentik.k3s-podman-testing.localhost:4962/application/o/radar/
- --auth-oidc-client-id=radar
- --auth-oidc-redirect-url=http://radar.k3s-podman-testing.localhost:4962/auth/callback
- --auth-oidc-groups-claim=entitlements
- --auth-oidc-scopes=openid,profile,email,entitlements
env:
- name: RADAR_AUTH_SECRET
value: radar-auth-secret
image: ghcr.io/skyhook-io/radar:1.7.6
I also checked for stale/chunked/bad session-cookie symptoms and did not see any relevant log lines:
kubectl -n radar logs deploy/radar --since=60m \
| rg -i 'HMAC|Session cookie|cookie|expired|chunk|too large|dropping ID token'
No matches.
The only Radar cookie present after a working login was radar_session.
Additional context
Using workaround for #981:
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "authentik.k3s-podman-testing.localhost"
containers:
- name: authentik-issuer-loopback
image: ghcr.io/nicolaka/netshoot:v0.15
command:
- socat
args:
- TCP-LISTEN:4962,fork,reuseaddr
- TCP:authentik-server.authentik.svc.cluster.local:80
In-pod reachability looked stable:
50/50 requests to /.well-known/openid-configuration returned 200
connect time: ~0.0002–0.0009s
total time: ~0.53–0.86s
POST /application/o/token/ without form data returned:
code=400 total=0.084344
This looks like a frontend auth-flow issue rather than an IdP reachability issue.
In Firefox DevTools, the initiator for /auth/login is the JS bundle. During the failing phase, radar_oidc_state changes repeatedly on reload/redirect. This suggests multiple protected API 401s during SPA boot independently trigger /auth/login, which repeatedly overwrites the single OIDC state cookie before earlier callbacks complete.
Possible fixes:
- Frontend: single-flight OIDC login redirects globally.
- Frontend: do not redirect independently from every protected API
401 during initial boot.
- Frontend: gate protected bootstrap API calls behind one auth/session check.
- Backend hardening: make
/auth/login idempotent while a valid radar_oidc_state already exists.
- Backend hardening: allow multiple outstanding OIDC states instead of one shared state cookie.
Describe the bug
When using OIDC auth, Radar can get stuck in a login loop during initial frontend boot.
A single browser tab repeatedly initiates
/auth/loginfrom the JavaScript bundle after protected/api/*requests return401. Each/auth/logingenerates a newradar_oidc_statecookie. Because that cookie changes on each redirect/reload, callbacks from earlier OIDC redirects can fail or be canceled.Eventually one callback may “win” and the app starts working, but the initial login flow is flaky and noisy.
To reproduce
Steps to reproduce the behavior:
1.7.6with OIDC enabled./traffic./api/connection,/api/capabilities,/api/namespaces,/api/portforwards, etc. returning401./auth/loginbeing initiated by the JS bundle.radar_oidc_statecookie changing repeatedly across reloads/redirects.400or500, or token exchange cancellation.200.Expected behavior
Radar should start at most one OIDC login flow during frontend boot.
Repeated protected API
401s from the same SPA load should not independently initiate multiple/auth/loginnavigations or repeatedly overwriteradar_oidc_state.After a successful OIDC callback, the browser should land back in the app with a valid session, and API calls should return
200without repeated login redirects.Screenshots
Not included.
Diagnostics (optional)
ghcr.io/skyhook-io/radar:1.7.6v1.35.4+k3s11RADAR_AUTH_SECRET: configured and stableLogs
Deployment details:
I also checked for stale/chunked/bad session-cookie symptoms and did not see any relevant log lines:
No matches.
The only Radar cookie present after a working login was
radar_session.Additional context
Using workaround for #981:
In-pod reachability looked stable:
This looks like a frontend auth-flow issue rather than an IdP reachability issue.
In Firefox DevTools, the initiator for
/auth/loginis the JS bundle. During the failing phase,radar_oidc_statechanges repeatedly on reload/redirect. This suggests multiple protected API401s during SPA boot independently trigger/auth/login, which repeatedly overwrites the single OIDC state cookie before earlier callbacks complete.Possible fixes:
401during initial boot./auth/loginidempotent while a validradar_oidc_statealready exists.