fix(auth): meaningful error when ClickHouse refuses an authenticated user#11
Merged
Merged
Conversation
…icated user A valid IdP login that ClickHouse won't authorize (no CH user, missing grants, or an unverifiable JWT) surfaced as "Session expired" on the login screen, and re-authenticating never helped. Root cause: authedFetch flagged any 401/403 as auth-expired. But getToken() already guarantees a non-expired bearer before the POST, so a 401/403 that survives the single refresh-retry means CH rejected a *valid* login — an authorization/identity problem, not session expiry. Now that case shows an accurate message that names the cause and appends ClickHouse's own reason (e.g. "Code: 516 ... Token could not be verified"). Genuine expiry (no token, or expired + refresh failed) keeps its own path, reworded to "Your session expired — please sign in again." - core/stream.js: new pure authDeniedMessage(status, reason) - net/ch-client.js: classify valid-token 401/403 as authorization denial, passing CH's reason to onSignedOut - ui/app.js: onSignedOut(detail) renders the detail, else the expiry default Verified live on antalya by injecting a non-expired but unverifiable token: the login screen shows the authorization message + AUTHENTICATION_FAILED reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QennTvGKAtJZrv9EpQagef
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When a user signs in via the IdP successfully but ClickHouse won't authorize them — no matching CH user, missing grants, or a JWT it can't verify — the app showed "Session expired" and bounced to the login screen. The session wasn't expired, and re-authenticating never helped. The user just saw repeated
403s with an unhelpful message.Root cause
authedFetch(src/net/ch-client.js) flagged any 401/403 as "auth expired." But by the time it POSTs,getToken()has already guaranteed a valid, non-expired bearer (it refreshes, or returns null and the caller signs out). So a 401/403 that survives the single refresh-retry means ClickHouse rejected a valid login — an authorization/identity problem, not expiry. The code nonetheless calledonSignedOut()→renderLogin(app, 'Session expired').Fix
Distinguish the two failure modes:
Changes:
core/stream.js— new pureauthDeniedMessage(status, reason)(reusesparseExceptionTextfor the server reason)net/ch-client.js— classify a valid-token 401/403 as authorization denial, pass CH's reason toonSignedOutui/app.js—onSignedOut(detail)renders the detail, else the expiry defaultTests
npm testgreen; per-file gate held —stream.jsandch-client.jsat 100%. AddedauthDeniedMessagecases, updated the ch-client 403 test to assert the message + server reason, and added an app.js test for bothonSignedOutmessage paths.Verification
Built and deployed to antalya + otel. Reproduced live on antalya by injecting a non-expired but unverifiable JWT (so
getToken()returns it and ClickHouse 403s it): the login screen shows the authorization message + the realAUTHENTICATION_FAILEDreason instead of "Session expired" (screenshot below).🤖 Generated with Claude Code
https://claude.ai/code/session_01QennTvGKAtJZrv9EpQagef