Skip to content

(#1061) Add jwt command to decode the user JWT in a creds file - #1750

Merged
ploubser merged 8 commits into
nats-io:mainfrom
SagarSingh2003:feat/jwt-decoder
Oct 20, 2026
Merged

ploubser merged 8 commits into
nats-io:mainfrom
SagarSingh2003:feat/jwt-decoder

Conversation

@SagarSingh2003

Copy link
Copy Markdown
Contributor

This PR references issue #1061

What it covers :

  • from a creds file (passed through the --creds flag or from the context) decodes the jwt's header and claims and prints prettified json on the terminal
  • --json flag allows users to pipe the output to tools like jq
  • (bugfix) :
    • file : nats/tests/test_helpers.go
    • function : matchRecursive
    • bug : if actual and expected is 1.08756e+05 the + and . is treated as a command and not as a literal
    • fix : add a == check in default case before the regex matching
  • it converts the iat into utc timestamp and puts it in issuedAt field
  • only the JWT block is read, the NKEY seed is never parsed, and errors don't echo file contents. There are tests that assert it

Not included, to keep this PR small: raw JWT string / JWT-file input,
human-friendly timestamp annotations, signature verification, jq-style
field walking, colors.

Question: should --json print only the token's exact claims? Right now
it's a combined object (header, claims, issuedAt), and decoding through
GenericClaims may drop fields it doesn't model. Happy to change it.

Note : it does not verify the signatures and is not a proof that the jwt is valid

@ripienaar ripienaar left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this contribution, generally please review the prevailing style of the project and make sure your code looks like it belongs in the project.

Other than that I'd say there's some extra code here that isn't probably already available in the jwt package

Comment thread cli/jwtDecoder.go Outdated
Comment thread cli/jwtDecoder.go Outdated
Comment thread cli/jwtDecoder.go Outdated
Comment thread cli/jwtDecoder.go Outdated
Comment thread cli/jwtDecoder.go Outdated
return base64.RawURLEncoding.DecodeString(s)
}

func (c *decodeJwtCmd) DecodeCreds(jwtStr string) error {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I bet there are already helpers for this in the jwt library, ParseDecoratedJWT() maybe?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for the reviews, i am working on them, i had a question there is another helper DecodeGeneric that exctracts just the claims, should i just go ahread and use it and skip adding decoded headers to output? or should i keep the decoded headers, i am asking from a ux point of view do users need to see the decoded headers ?

@ripienaar ripienaar Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my mind this feature should be built like this:

  • you find out the type of the JWT (user, account, operator etc)
  • you render each with a user friendly column interface compatible with the overall CLI design
  • you have a --json flag as optional for those who want it

dumping jwt to json is not the UI, its why this has sat unimplemented so long because I just dont think this is a UX I want here, so I am not inclined to say we should not accept it as designed here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i understand the direction now , i apologise if this is a newbie question but , currently i get the user jwt from a .creds file , the operator and account info is usually present in the server.conf in the server , so do i need to fetch it or can i simply allow the users to give me a .jwt file path ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the original issue mentions various places to get JWT from - creds file yes that would be a user, but also a arbitrary JWT and we have quite a few types of JWT from different places including just a .jwt file

Comment thread cli/jwtDecoder.go Outdated
Comment thread cli/jwtDecoder.go Outdated
Comment thread cli/jwtDecoder.go Outdated
@SagarSingh2003

Copy link
Copy Markdown
Contributor Author

@ripienaar i have rewritten the whole thing, keeping in mind all the reviews that you gave, this is how the command output looks like :
image

  • it accepts either a jwt from the terminal , or any file that contains jwt or a .creds file
  • a --json flag that is optional

@ripienaar

Copy link
Copy Markdown
Collaborator

Thank you @SagarSingh2003 this looks pretty good, we'll do a small fixup PR after appreciate your contribution!

@ploubser

Copy link
Copy Markdown
Collaborator

Thanks @SagarSingh2003, I've pushed a small commit to fix a linter issue. If you wouldn't mind signing your commits we can go ahead and merge this PR.

@SagarSingh2003

SagarSingh2003 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Thank you @ripienaar and @ploubser for the review, @ploubser i rebased the commits and signed all of them , just a heads up that i ended up signing your commits as well so the hash has changed. . If you have the branch checked out locally, git fetch && git reset --hard origin/feat/jwt-decoder will sync you up.

@ploubser
ploubser merged commit 77205f1 into nats-io:main Oct 20, 2026
7 checks passed
@ploubser

Copy link
Copy Markdown
Collaborator

Thanks again @SagarSingh2003. Sorry it took me so long to merge, I was out for a few days.

Appreciate the contribution :)

@SagarSingh2003

Copy link
Copy Markdown
Contributor Author

@ploubser i went through the cleanup pr , that was a lot of work sorry for that, will do better next time. you are awesome

@ploubser

Copy link
Copy Markdown
Collaborator

@SagarSingh2003 no problem at all, your changes gave me a good opportunity to extract some shared code :) It looks like a lot more work than it really was!

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.

3 participants