fix(web): refresh expired OIDC tokens before API calls
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled

The overview background graph and the Knowledge Base graph both rendered
empty because the SPA's OIDC access token expired (~5 min TTL) and was
never refreshed. fetchWithAuth called getToken() synchronously (no refresh);
ensureToken returned the stale token without refreshing; storeTokens
discarded expires_in; the resulting 401 made fetchGraph return null and
both graphs drew nothing, with no error surfaced.

- oidc.ts: track expiresAt from expires_in; getToken() returns null within
  30s of expiry; ensureToken/initOIDC refresh instead of returning stale
  tokens; isOIDCConfigured no longer claims configured on expired-only state
- config.ts: fetchWithAuth awaits ensureToken (refresh on demand), falls
  back to static token if OIDC can't yield one, flushes OIDC session on 401;
  sseUrl is async + refreshes before constructing the EventSource
- stores/events.ts: connect() awaits the now-async sseUrl
This commit is contained in:
2026-07-14 20:42:07 +02:00
parent 3de359b85f
commit 3b98097f58
6 changed files with 98 additions and 21 deletions

View File

@@ -6,6 +6,22 @@ e2e-validated, committed (`337d577`), pushed to `main`, and deployed to
next blocker** (refuse `complete_task` without writeback — the knowledge
loop is still drifting).
**2026-07-14 (PM) — OIDC token-refresh fix (unplanned, root-cause for the
empty graph symptom):** the overview background graph and the Knowledge Base
graph both rendered empty because the SPA's OIDC access token expired
(~5 min TTL) and was never refreshed. `fetchWithAuth` called `getToken()`
synchronously (no refresh); `ensureToken` returned the stale token without
refreshing; `storeTokens` discarded `expires_in`; and the resulting 401
made `fetchGraph` return `null` → both graphs drew nothing, with no error
surfaced. Fixed structurally in `web/src/lib/oidc.ts` +
`web/src/lib/config.ts` + `web/src/lib/stores/events.ts`: tokens now carry
`expiresAt`, `getToken()` returns null within 30s of expiry, `fetchWithAuth`
awaits `ensureToken()` (refreshes on demand), `sseUrl` is async + refreshes
before constructing the EventSource, and a 401 flushes the OIDC session so
the static token fallback takes over. Build passes. Not yet committed or
deployed (pending operator verification). Not part of any numbered phase
above — filed here because it was the highest-impact surface symptom.
## Shipped (2026-07-14, v0.5.0 — commit 337d577, deployed)
| Fix | File(s) | Validation |

View File

@@ -17,7 +17,7 @@ went sideways, open an investigation.
| 2026-07-14 | [Session reliability & UX audit](2026-07-14-session-reliability-and-ux-audit.md) | Done — all 21 fixes deployed |
| 2026-07-14 | [Tool timeline in sidebar](2026-07-14-tool-timeline-sidebar.md) | Done — deployed v0.3.2 |
| 2026-07-14 | [Unified agent activity indicator](2026-07-14-unified-agent-indicator.md) | Done — deployed v0.3.3 |
| 2026-07-14 | [Post-fix session remainders: empty responses & plan drift](2026-07-14-post-fix-session-remainders.md) | In Progress — Phases A + B.1-B.3 + F.3 shipped, e2e-validated, committed (337d577), deployed v0.5.0; Phases C, D, E, F.1-F.2 remain (D.1 is the next blocker) |
| 2026-07-14 | [Post-fix session remainders: empty responses & plan drift](2026-07-14-post-fix-session-remainders.md) | In Progress — Phases A + B.1-B.3 + F.3 shipped, e2e-validated, committed (337d577), deployed v0.5.0; Phases C, D, E, F.1-F.2 remain (D.1 next blocker). **PM:** OIDC token-refresh fix (root-cause for empty graphs) implemented, not yet committed/deployed |
## Done