Fix regenerateAccessKey putting the wrong subject in the JWT - #3708
Merged
Conversation
accessKey.getName() is the access key's human-readable label (e.g.
"mcp"), not the RODA username - that's accessKey.getUserName().
createAccessKey correctly uses the username (via
accessKey.setUserName(id), consumed by the model service layer when it
generates the token); regenerateAccessKey built the JWT inline and used
the wrong field.
The bug is silent and severe: JwtUtils.generateToken signs a token
whose subject doesn't correspond to any real user. RODA's own
/authenticated endpoint doesn't reject this - it decodes the token,
fails to find a matching user, and returns a degenerate User shell
(id=null, name=null, uuid="user-null", guest=false, allRoles=[]) with
200 OK instead of erroring. Every tool/role check downstream then
silently sees a "real" but permission-less user rather than a clear
authentication failure. Any AccessKey regenerated via RODA's UI (the
Access Token tab's "regenerate" action, not "create") was affected -
only brand-new keys worked correctly.
Verified live: created an AccessKey, regenerated it via
POST /api/v2/members/users/access-keys/regenerate/{id}, decoded the
resulting JWT (sub now correctly "admin", not the key's label), and
confirmed GET /api/v2/members/users/authenticated with that token
returns the full admin identity and role list.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01263fsB7QYevDFgwAY8okcq
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.
Summary
accessKey.getName()is the access key's human-readable label (e.g. "mcp"), not the RODA username - that'saccessKey.getUserName().createAccessKeycorrectly uses the username;regenerateAccessKeybuilt the JWT inline and used the wrong field.JwtUtils.generateTokensigns a token whose subject doesn't correspond to any real user. RODA's own/authenticatedendpoint doesn't reject this - it decodes the token, fails to find a matching user, and returns a degenerateUsershell (id=null, name=null, uuid="user-null", guest=false, allRoles=[]) with200 OKinstead of erroring. Every downstream role check then silently sees a "real" but permission-less user rather than a clear authentication failure.Test plan
POST /api/v2/members/users/access-keys/regenerate/{id}, decoded the resulting JWT (subnow correctly the username, not the key's label), and confirmedGET /api/v2/members/users/authenticatedwith that token returns the full identity and role list.Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com