Every time I needed to inspect a JWT, I ended up doing the same thing: paste it into a website I half-trust, squint at the payload, then close the tab feeling vaguely guilty. I wanted a local tool, scriptable, that could both decode tokens and mint them for testing. So I wrote jwt-cli.
What it does
jwt-cli is a small Go binary that encodes and decodes JWT tokens from the command line. Nothing leaves your machine, and it covers every algorithm I actually run into:
- HMAC: HS256, HS384, HS512
- RSA: RS256, RS384, RS512
- ECDSA: ES256, ES384, ES512
That’s it. No web UI, no telemetry, no online service. Just a binary you can pipe into and out of.
Install
The easiest path on macOS or Linux is Homebrew:
brew tap sgaunet/homebrew-tools
brew install sgaunet/tools/jwt-cli
Or grab a binary from the releases page and drop it in /usr/local/bin. There’s also a Docker image (sgaunet/jwt-cli:latest) which is mostly useful as a COPY --from= source in your own Dockerfiles.
Encoding a token
The simplest case — sign a payload with an HMAC secret:
jwt-cli encode hs512 \
--payload '{ "email": "myemail@me.com" }' \
--secret "myAwesomeSecret"
That spits out the familiar three-segment token. Change hs512 to rs256 and pass --private-key to sign with an RSA key instead. The subcommand selects the algorithm — there’s no clever auto-detection, which I consider a feature.
Decoding and verifying
Decoding is the inverse, and the CLI verifies the signature for you:
# Wrong secret? You get told.
jwt-cli decode hs512 --secret "wrong secret" --token "$TOKEN"
# signature is invalid
# Right secret? You get the JSON payload.
jwt-cli decode hs512 --secret "myAwesomeSecret" --token "$TOKEN"
# {
# "email": "myemail@me.com"
# }
The exit code reflects the verification result, which is what you want when you’re shoving this into a CI step.
Generating keys
For RSA and ECDSA you’ll need a keypair. Rather than make you remember the openssl incantations, jwt-cli genkeys prints them for the algorithm you’re targeting. Here’s the ES256 example straight from the README:
openssl ecparam -genkey -name prime256v1 -noout -out ES256-private.pem
openssl ec -in ES256-private.pem -pubout -out ES256-public.pem
Run jwt-cli genkeys and it gives you the equivalent for every supported algorithm. Small thing, but I no longer have to dig through old notes.
Shell completion
The CLI ships completions for bash, zsh, fish and PowerShell:
jwt-cli completion zsh > ~/.zsh/completions/_jwt-cli
After that, jwt-cli encode <TAB> lists the algorithms, and jwt-cli decode rs256 --private-key <TAB> filters to .pem and .key files. Nice for the muscle memory.
Where to grab it
- Source: github.com/sgaunet/jwt-cli
- License: MIT
- Releases: prebuilt binaries for Linux, macOS and Windows
It’s open source, MIT-licensed, and small enough to read end to end if you’re curious how the signing pieces fit together. If it saves you one trip to a sketchy online JWT debugger, it’s earned its keep.