You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add oauth.username_claim (--oauth-username-claim / MCP_OAUTH_USERNAME_CLAIM)
to select which JWT claim becomes the ClickHouse Basic-auth username on the
ch-jwt-verify sidecar path. Unset keeps today's behavior (email + namespaced
*/email fallback); when set, basicUsernameFromJWT does a strict top-level
lookup of that single claim via oauth.UsernameFromExtra and fails closed on a
missing/empty/non-string value, naming the claim in the error. The value is an
unverified hint only — CH/sidecar still validate the JWT. Bearer path and
role_claim/role_filter are unchanged.
Bumps go-mcp-oauth-sdk to the release carrying UsernameClaim + UsernameFromExtra.
Docs: docs/oauth_authorization.md + helm values.
Closes#152
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SV1MFJRKvA1zWsacpeieoE
If your ClickHouse uses `token_processors`, altinity-mcp will detect
@@ -283,6 +301,13 @@ server:
283
301
role_claim: ""# e.g. "https://clickhouse/roles"
284
302
role_filter: ""# optional; e.g. "^anon_" (empty = activate all claim roles)
285
303
304
+
# JWT claim used as the ClickHouse Basic-auth username on the sidecar path.
305
+
# Empty = default `email` claim + namespaced */email fallback. When set, a
306
+
# strict top-level lookup of this single claim is used and a missing/empty/
307
+
# non-string value fails closed. Must match the sidecar's
308
+
# identity.username_claim. Applies only to the Basic path, not Bearer.
309
+
username_claim: ""# e.g. "username", "preferred_username", "sub"
310
+
286
311
# Token lifetimes (broker mode)
287
312
access_token_ttl_seconds: 3600
288
313
refresh_token_ttl_seconds: 2592000# 30 d
@@ -313,6 +338,7 @@ server:
313
338
| `upstream_offline_access` | Request `offline_access` upstream so the IdP consent screen offers long-lived sessions. Default `false`. |
314
339
| `role_claim` | JWT claim holding a JSON array of ClickHouse role names to activate per request (e.g. `https://clickhouse/roles`). Empty disables. Read from the validated token's namespaced/custom claims. |
315
340
| `role_filter` | **Optional** regex narrowing which `role_claim` roles are activated (e.g. `_mcp$`). When empty, **all** roles in the claim are activated (the IdP curates the set; CH re-validates the token and enforces grants). Only ever narrows; an empty *resolved* set (claim absent/empty, or filter matched nothing) fails closed — request denied, no fallback to the full grant. HTTP protocol only; applies in both Bearer and Basic/sidecar paths. **Anchor it** (`^…`/`…$`) — it's a partial match, so an unanchored `anon` would also match `not_anon_real`. |
341
+
| `username_claim` | JWT claim used as the ClickHouse Basic-auth username on the `ch-jwt-verify` sidecar path. Empty (default) = `email` claim with a namespaced `*/email` fallback. When set (e.g. `username`, `preferred_username`, `sub`), a strict top-level lookup of that single claim is used and a missing/empty/non-string value **fails closed** — never falling back to another identity. An explicit `email` is strict (no namespaced fallback). Unverified hint only (CH/sidecar still validate). **Must match the sidecar's `identity.username_claim`.** Basic path only; no effect on Bearer. |
0 commit comments