Skip to content

fix: fix Web Console hanging or signing out when SSO tokens expire - #617

Open
glasstiger wants to merge 2 commits into
mainfrom
feat/qwp-entra-token-provider
Open

glasstiger wants to merge 2 commits into
mainfrom
feat/qwp-entra-token-provider

Conversation

@glasstiger

@glasstiger glasstiger commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Tandem: questdb/questdb#7799, questdb/questdb-enterprise#1267

Extracted from #603. This PR contains only the console changes the two server PRs depend on; everything else stays in #603.

Why the server change needs it

questdb/questdb#7799 and questdb/questdb-enterprise#1267 tie HTTP sessions to the credentials that opened them. A request that carries the qdb_session cookie and an Authorization header the server rejects is no longer served from the cookie: it gets 401, and the session is closed. Until now, that cookie fallback hid stale bearers from the console. From now on, the console has to send a valid bearer and recover from a 401 itself.

Changes

  • ID-token bearers refresh on their own expiry. With acl.oidc.groups.encoded.in.token=true the bearer is the ID token. The console now schedules its renewal from the ID token's exp claim, instead of the access token's expires_in. A provider that omits the ID token gets an explicit "Missing ID token" error instead of Bearer undefined.
  • The bearer is read when each request is sent. That covers SQL, validation, CSV check/import and preference requests. Stored REST/Basic credentials from another tab no longer replace an SSO bearer, and the login method is remembered per tab.
  • Bounded, shared token refresh. This also fixes the original hang, where a failed refresh left every query waiting forever.
    • Queries wait up to 10s for a renewal. A rotating refresh can still complete within 60s.
    • Transport, timeout, 429 and 5xx failures back off without logging out.
    • After a failed renewal, an expired bearer is never sent; such requests fail locally with "the request was not sent".
  • 401 recovery.
    • A 401 executed no SQL, so the console refreshes and resends once.
    • A 401 answered for an older bearer no longer logs the user out. Only a rejection of the current bearer does.
    • An OAuth rejection of the refresh still returns the user to sign-in.
  • Failure UX.
    • A persistent renewal warning with "Sign in again".
    • A recovery view with Retry, instead of a blank console, when the startup check fails.
    • Sign-in failures (unreachable or slow token endpoint, invalid response) are reported on the login page.
  • Telemetry shares the console client. It no longer sends a bearer captured at startup, which the server would now reject with a 401 and log the user out. It never starts a refresh of its own.
  • Read-only requests are marked as background. Logout and "Sign in again" then only warn about statements and writes that were actually sent.
  • Enterprise e2e lane.
    • .github/workflows/enterprise_e2e.yml dispatches the Azure lane that questdb-enterprise#1267 adds.
    • The lane picks the Enterprise branch with the same name as the UI branch. This branch is named feat/qwp-entra-token-provider for that reason, so it runs against the tandem server.
    • e2e/commands.js execQuery now sends the stored REST token for Enterprise password logins.
  • e2e/questdb is bumped to OSS master (e4da5b45), the same commit fix: fix Web Console hanging when SSO token refresh fails #603 pins. "Check if OSS is on master" requires every PR's pointer to be within 5 commits of OSS master, and main's pointer is 27 commits behind.

Left in #603

Kept out of this PR because they aren't needed for the server change:

  • logout store reset and session isolation in the editor, scripts, AI chat, notebooks, schema, CSV import and charts;
  • loading-notification history changes;
  • notebook persistence and the Dexie v10 index;
  • the Alt+N notification shortcut, toast focus and theme tokens;
  • schema-tree keyboard handling;
  • the Settings error view redesign;
  • AI chat deletion race, legacy grid stale pages, request-limiter queue.

The hybrid files carry only the part needed here; #603 keeps the rest.

  • Toast/index.tsx: only REFRESH_FAILED_TOAST_ID.
  • refreshFailedWarning.tsx: no Alt+N instructions.
  • index.tsx: only the ToastContainer move.
  • Import, Result, chart, quick-vis, Schema and the notebook refresh engine: only the background read flag and the ssoAuthState rename.
  • auth.spec.js: only the tandem tests. The "Sign in again" focus test clicks the warning directly instead of using Alt+N.

Once this is merged, merge main into #603 and resolve its 6 conflicts (auth.spec.js, Toast/index.tsx, refreshFailedWarning(.test).tsx, AuthProvider.test.tsx, Schema/index.tsx) with #603's version. I rehearsed this: the result is identical to #603's current tree, and its diff shrinks to the remaining changes.

Merge order

  1. feat(qwp): add refreshing token providers for Entra ID authentication java-questdb-client#102
  2. This PR. Then release a console that includes it.
  3. fix(core): breaking change 💥 - tie HTTP sessions to their credentials and stop reused JSON parsers growing their copy buffer - OSS tandem questdb#7799, after bumping web.console.version to that release
  4. questdb/questdb-enterprise#1267

The server PRs currently reference #603 for step 2. Point them at this PR.

Validation

At 58799115, plus the submodule-only commit 58add5e2:

  • yarn typecheck, yarn lint and yarn build pass.
  • yarn test:unit passes: 2,878 tests in 141 files.
  • yarn cypress run --spec 'e2e/tests/auth/*.spec.js' --browser electron against the production preview: 43 passing (39 auth, 4 unauthorized-recovery).

Not run locally:

  • the console e2e suite against a real server (CI runs it);
  • the Enterprise lane, which needs ENTERPRISE_E2E_ENABLED and the pipeline from questdb-enterprise#1267. As configured there, it uses groups.encoded.in.token=false, so the ID-token path is covered only by unit tests and the stubbed browser tests.

Extracted from #603: the console half of questdb/questdb#7799 and
questdb/questdb-enterprise#1267. Those PRs stop serving a request from the
qdb_session cookie when its Authorization header is rejected, so an expired
or stale bearer now gets a 401 and closes the session instead of being masked.

- Refresh an ID-token bearer (acl.oidc.groups.encoded.in.token=true) by the
  ID token's exp claim rather than the access token's expires_in, and report
  a missing ID token instead of sending "Bearer undefined".
- Read the bearer at send time for SQL, validation, CSV check/import and
  preference requests, and never let stored REST/Basic credentials replace
  an SSO bearer.
- Coordinate token refresh in one bounded, cancellable place: queries wait up
  to 10s, a rotating refresh may still land within 60s, transient failures
  back off without logging out, and an expired bearer is never sent after a
  failed renewal (fixes the refresh deadlock that froze every query).
- Recover from a rejected bearer: refresh and resend once (a 401 executed no
  SQL), ignore 401s answered for an older bearer, and log out only when the
  current bearer is rejected.
- Show a renewal warning and a recovery view with Retry/Sign in again instead
  of a blank console, and report sign-in failures.
- Share one client between the console and telemetry so telemetry never sends
  a stale bearer, and mark read-only requests as background so logout warnings
  only count statements and writes.
- Dispatch the Enterprise Web Console e2e lane added by
  questdb-enterprise#1267, send the stored REST token in e2e execQuery, and
  extend the unit and stubbed browser auth tests.
@glasstiger glasstiger added bug Something isn't working web-console Issues relevant to "web-console" package security labels Oct 19, 2026
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Web Console deploy preview

Preview Commit Logs
https://pr-617--web-console.netlify.app 688d262 build log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working security web-console Issues relevant to "web-console" package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant