Repository navigation
feat(auth): API authentication with admin and read-only roles - #2
Merged
Merged
Conversation
Implements F1 from the deep analysis — the high-severity finding that the entire API was unauthenticated with permissive CORS (WebConfig.java). - kview.auth.mode=none (default): zero-config localhost behavior, exactly as before - kview.auth.mode=token: static bearer tokens via KVIEW_AUTH_TOKENS (TOKEN = admin, TOKEN:readonly = read-only) - kview.auth.mode=oidc: JWTs from any OIDC issuer (issuer-uri/jwk-set-uri via spring.security.oauth2.resourceserver.jwt.*), optional audience check, role decided by a configurable claim (default roles: kview-admin) - roles: reads under /api/** need any role; mutations (POST/PUT/DELETE except the read-shaped posts browse/decode/encode/test) need admin; static UI and /actuator/health stay public - CORS stays permissive only in none-mode; authenticated modes close it unless KVIEW_AUTH_ALLOWED_ORIGINS lists origins - SSE clients (EventSource cannot send headers) can pass ?access_token= - web UI prompts for the token on 401 (top-bar button to set/clear) - CLI: --token flag / KVIEW_TOKEN env on every call incl. tail - MCP server: KVIEW_TOKEN env on all tool calls - tests: 13 new (token-mode 401/403/200 matrix, read-shaped POSTs, public static/health, default-mode regression, JWT role converter) — full suite 43/43 - docs: README Authentication section + config rows, SECURITY.md rewrite
This was referenced Sep 26, 2026
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.
Implements F1 from the deep analysis — the high-severity finding that the entire API is unauthenticated with
allowedOriginPatterns("*")CORS, meaning any web page an operator visits could silently drive destructive endpoints (topic delete, group delete, offset resets) from their browser.Stacked on #1 (touches
WebConfig.java,CHANGELOG.md,README.mdthere) — merge #1 first.Design
kview.auth.mode— off by default, so the zero-config localhost story is unchanged (regression-tested byNoAuthByDefaultTest):none(default)tokenKVIEW_AUTH_TOKENS(TOKEN= admin,TOKEN:readonly= read-only).oidcspring.security.oauth2.resourceserver.jwt.issuer-uri), optionalaudcheck, admin vs read-only decided by a configurable claim (roles: kview-adminby default); every other valid token is read-only (least privilege).Role rules (one place,
SecurityConfig): reads under/api/**need any role; mutations need admin; POSTs that are semantically reads (**/browse,**/decode,**/encode,**/test) stay available to read-only. Static UI and/actuator/healthstay public. 401/403 answers are JSON in the API's existing{error, detail}shape.CORS: permissive only in
nonemode; authenticated modes close it unlessKVIEW_AUTH_ALLOWED_ORIGINSlists origins — this kills the drive-by-mutation hole at the root.SSE:
EventSourcecannot send headers, so?access_token=is accepted (rewritten to the Authorization header by a filter) — live tail works in both modes.Clients: web UI prompts for the token on 401 plus a 🔑 top-bar button; CLI takes
--token/KVIEW_TOKEN; MCP server takesKVIEW_TOKEN.Verification
./mvnw -B test).java -jarwith token mode: no token → 401, wrong token → 401, read-only GET → 200, read-only DELETE → 403, admin DELETE → past authorization, UI/health public, andnode cli/kview.mjs --token view clustersworks against the running server.