Skip to content

feat(auth): multi-IdP config.json + login provider picker (phase 1)#4

Merged
BorisTyshkevich merged 1 commit into
mainfrom
feat/multi-idp-config
Jun 20, 2026
Merged

feat(auth): multi-IdP config.json + login provider picker (phase 1)#4
BorisTyshkevich merged 1 commit into
mainfrom
feat/multi-idp-config

Conversation

@BorisTyshkevich

Copy link
Copy Markdown
Collaborator

Phase 1 of multi-IdP support: config.json can list several OAuth providers, and the login screen shows one button per IdP. Fully backward-compatible and opt-in.

Config shape

{ "idps": [
    { "id": "google", "label": "Google",   "issuer": "https://accounts.google.com", "client_id": "" },
    { "id": "acme",   "label": "Acme SSO", "issuer": "https://acme.auth0.com",      "client_id": "", "client_secret": "" }
  ] }

A bare single object (today's format) is treated as a one-IdP list — otel/antalya configs are unchanged. Per-entry id/label are optional (default: issuer host).

Changes

  • oauth-config.js: split loadOAuthConfigloadConfigDoc (fetch + normalize a list, or wrap a bare object) + resolveIdp (per-IdP OIDC discovery). oauth.js untouched.
  • app.js: resolveConfig resolves the selected IdP; the choice persists as oauth_idp in sessionStorage (survives the OAuth redirect, like oauth_state) and drives token exchange / refresh / per-IdP bearer+ch_auth. Adds login(idpId), selectIdp, loadIdps; signOut clears the selection.
  • login.js: one "Sign in with …" button per IdP when >1 (async-loaded; falls back to the single button for 1 IdP or a load failure).
  • ClickHouse side: no change — CH already validates each inbound JWT against the token_processor matching its iss, so offering several IdPs needs no extra CH wiring.
  • Docs: config.json.example + README "Configuring OAuth → Multiple IdPs".

Verification

  • In-browser (built bundle): a 3-IdP config renders "Sign in with Google / Acme SSO / Keycloak"; single-IdP shows the lone button (regression).
  • npm test → 360 pass; oauth-config.js + login.js at 100%, app.js within its gate.

Phase 2 (auto-generating config.json from ClickHouse token_processors) builds on this list shape.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QennTvGKAtJZrv9EpQagef

config.json may now list several OAuth IdPs; the login screen shows one button
per provider ("Sign in with <label>"). A bare single object is still accepted
(treated as a one-IdP list), so existing otel/antalya configs are unchanged.

- oauth-config.js: split loadOAuthConfig into loadConfigDoc (fetch + normalize a
  list, or wrap a bare object; id/label default to the issuer host) and
  resolveIdp (per-IdP OIDC discovery). oauth.js untouched.
- app.js: resolveConfig resolves the *selected* IdP; the choice persists as
  `oauth_idp` in sessionStorage (survives the OAuth redirect like oauth_state),
  driving token exchange/refresh and per-IdP bearer/ch_auth. login(idpId),
  selectIdp, loadIdps; signOut clears the selection.
- login.js: one button per IdP when >1 (async-loaded; single fallback on 1 or
  load failure). CH side needs no change — it validates each JWT against the
  token_processor matching its `iss`.

Docs: config.json.example + README document the list shape. Verified in-browser:
3-IdP picker renders; single-IdP regression intact. 360 tests pass;
oauth-config/login at 100%, app.js within gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QennTvGKAtJZrv9EpQagef
@BorisTyshkevich BorisTyshkevich merged commit fffca86 into main Jun 20, 2026
2 checks passed
@BorisTyshkevich BorisTyshkevich deleted the feat/multi-idp-config branch June 22, 2026 16:43
BorisTyshkevich added a commit that referenced this pull request Jun 22, 2026
…s via Chart.js

Replace the single hard-wired bar chart with a real chart surface matching the
Claude Design handoff: a config bar (Type / X / Y / multi-series toggle /
group-by Series), an autoChart heuristic that classifies columns from their
ClickHouse types (temporal → line, categorical → horizontal bar, ordinal →
column), and five renderers (h-bar / column / line / area / pie) with
multi-series and group-by pivot, themed to the CSS tokens.

Rendering now uses Chart.js — the one bundled runtime dependency, inlined into
dist/sql.html so the page still makes zero third-party requests. This relaxes
CLAUDE.md hard rule #4 (recorded there, in the README, and build.mjs). To keep
the coverage model intact, all role/axis/pivot/scale math and the Chart.js
config builder are pure in src/core/chart-data.js (100%), and the `new Chart()`
call is an injected seam (app.Chart) so the DOM wrapper stays fully tested.

Chart config persists per query tab (tab.chartCfg/chartKey), re-derived on
schema change; live Chart instances are destroyed on re-render to avoid leaks.

npm test: 488 passed, per-file gate green. Build: 313 KB self-contained artifact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wtzg34E1iGzKm11TArRpko
BorisTyshkevich added a commit that referenced this pull request Jun 23, 2026
…t, qualified fallback, doc-cache, single tokenize (#26, #27)

Five findings from a follow-up manual review; verified live on otel.

Correctness:
- Hover docs now resolve the hovered word from the string/comment-masked text
  (host.maskedValue()), so hovering a function/keyword inside a string or comment
  no longer pops a phantom doc card — consistent with signature help (#1).
- Signature help strips the optional-param brackets ClickHouse uses
  (`name(a, b[, c])`) before splitting on commas, so args render cleanly and the
  active-arg highlight aligns (was showing `offset[` / `length]` for substring) (#2).
- completionContext only flags `qualified` when a real identifier precedes the
  dot; a bare dot (`.col`, `count().c`) now falls back to normal completion
  instead of an empty dropdown (#4).
- loadEntityDoc returns null on a query FAILURE vs '' for genuinely-no-doc, and
  entityDoc caches the latter but drops the former — a transient error no longer
  permanently suppresses a function's hover/footer doc for the session (#8).

Performance:
- The keystroke path tokenizes the buffer ONCE and shares the token list between
  the syntax highlighter and the literal mask, instead of two full passes per
  keystroke. maskFromTokens()/renderTokensInto() consume a token list; the editor
  memoizes it by (text, refData) so it re-tokenizes when server keyword/func sets
  arrive after connect (#5).

Tests cover each: hover-in-literal, bracketed-param signature split, bare-dot
fallback, failed-doc retry, and re-highlight-on-refData-change (the shared-token
cache invalidation). All gated layers stay 100/100/100/100 (ui glue within its
functions>=95 / branches>=90 floor).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGBS74oUsXarGkCRQKEFLu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant