A super fast CLI tool to decode and encode JWTs built in Rust

A super fast CLI tool to decode and encode JWTs built in


A super fast CLI tool to decode and encode JWTs built in Rust.

jwt-cli is a command line tool to help you work with JSON Web Tokens (JWTs). Like most JWT command line tools out there, you can decode almost any JWT header and claims body. Unlike any that I've found, however, jwt-cli allows you to encode a new JWT with nearly any piece of data you can think of. Custom header values (some), custom claim bodies (as long as it's JSON, it's game), and using any secret you need.

On top of all that, it's written in Rust so it's fast and portable (windows, macOS, and linux supported right now).


Install jwt-cli via Homebrew (macOS), Cargo (cross-platform), and FreshPorts (FreeBSD). If you intend to use one of these methods, skip ahead.

You may also install the binary from the release page, if you're unable to use Homebrew or Cargo install methods below.

Only 64bit linux, macOS, and Windows targets are pre-built. Sorry if you're not on one of those! You'll need to build it from the source. See the contributing section on how to install and build the project.

You should install it somewhere in your $PATH. For Linux and macOS, a good place is generally /usr/local/bin. For Windows, there isn't a good place by default :(.



If your system supports it, you can install via Cargo. Make sure you have Rust and Cargo installed, following these instructions before proceeding.

The binary installs to your Cargo bin path (~/.cargo/bin). Make sure your $PATH environment variable includes this path.


If you're on FreeBSD, you can use the pkg tool to install jwt-cli on your system.

Big thanks to Sergey Osokin, the FreeBSD contributor who added jwt-cli to the FreeBSD ports tree!


jwt-cli is also available on Windows, macOS, and Linux using GoFish. See gofi.sh for instructions for getting GoFish.

After installing GoFish, run jwt-cli with:

Arch Linux

jwt-cli is available in the Arch Linux community repository and can be installed via pacman:


For usage info, use the help command.

Usage as a pipe

The - argument tells jwt-cli to read from standard input:

It's useful when you're dealing with a chain of shell commands that produce a JWT. Pipe the result through jwt decode - to decode it.


I welcome all issues and pull requests! This is my first project in rust, so this project almost certainly could be better written. All I ask is that you follow the code of conduct and use rustfmt to have a consistent project code style.

To get started you'll need rustc and cargo on your system. If they aren't already installed, I recommend rustup to get both!

Building and running the project

Once you have both installed, I recommend running the tests to make sure all is well from the start.

If it built without any errors, you should be able to run the command via cargo.

Or, if you prefer a release build:

Code of conduct



Contributors ✨

Thanks goes to these wonderful people (emoji key):

Mike Engel
πŸ’» πŸ’¬ πŸ“– πŸ€” 🚧 πŸ‘€ ⚠️ πŸ›

Kyle Burton

Aaron Schaef

πŸ’» ⚠️

Mat Kelly
πŸ’» πŸ›


Ben Berry

Kevin Lanni

Kosta Krauth
πŸ’» ⚠️ πŸ“–

πŸ’» πŸ€” ⚠️

Liz Frost

Carl Harris
πŸ’» ⚠️

Yusuke Kominami
πŸ’» πŸ“–

This project follows the all-contributors specification. Contributions of any kind welcome!


Collection of the latest Issues



Comment Icon0


EdDSA is currently not a supported algorithm, it would be great if it could be, however I know that the algorithm support comes from a dependency. Since that is mostly outside the purview of this library, I will also propose a feature request to add a flag to ignore the algorithm (--ignore-alg or similar). My main use case is to just decode the JWT's payloadβ€”which of course doesn't require validation of the algorithm or the headers at all. It would certainly be nice to have, but I'm wondering if it makes sense to block the ability to decode the payload.

Steps to reproduce

jwt decode "jwt.encoded.with.EdDSA" outputs the following:

Expected behavior

The decoded JWT perhaps with a warning instead that the algorithm was not supported OR the ability to add a flag, e.g. jwt decode --ignore-alg "jwt.encoded.with.EdDSA", to decode and validate the payload.



Comment Icon1


It would be great if additional headers were displayed with standard ones.



Comment Icon1


I am trying to encode a token on Windows using the following command:

jwt encode --alg RS256 --exp "+60 sec" --iss <issuer>

I am getting the errors:

The same key in .pem format works with the same command when I run it on Mac. Any ideas why there is an issue on Windows?

Steps to reproduce

Download and extract release 4.0.0 (https://github.com/mike-engel/jwt-cli/releases/download/4.0.0/jwt-windows.tar.gz) Run above command on Windows machine

Expected behavior

Equivalent .pem secret works the same on Windows as it does on Mac.



Comment Icon1

decode allows supplying the -j (--json) flag to output JSON in the following format:

I propose adding a -j (--json) flag to encode as well which accepts JSON in the same format. That means, options such as typ, alg etc. should be inferred from the header object, as well as payload and so on.

Ideally, this should enable the following workflow:

... where modify-token can be replaced with whatever utility that modifies the JSON.



Comment Icon3

When no algorithm is given during signature validation, HS256 is used by default. This leads to an error message stating that the JWT has a different algorithm than the one the user provided. PR #133 improves on this by showing the algorithm specified in the JWT and the algorithm used for signature validation (HS256 per default) but still, this is not ideal.

I would therefore suggest to require the --alg parameter when a secret is given (-S).

Current behavior:

Expected behavior:

Even better, it would be nice to allow for specifying multiple valid algorithms like this:



Comment Icon1


This is related to use cases described in both #119 and #128.

I'd like to run jwt encode by providing my own JWKS instead of a plaintext --secret value. For example:

where MY_JWKS can be retrieved from some HTTPS endpoint or generated locally using the jose CLI:

and jwt-cli would use the JWK in the provided keyset by matching the mandatory --kid value.

Besides just adding support for the JWKS standard, it allows using 256-bit (or whatever size) base64-encoded secrets that is in the JWKS k value. The --secret parameter is currently unable to use a non-Unicode string value, throwing the following error if given a binary string:


Find the latest versions by id

5.0.3 - Apr 27, 2022


  • Added instructions for installing on Arch linux #181
  • Added repository information for crates.io #184
  • Updates dependencies

5.0.2 - Jan 20, 2022


  • Fixes parsing of systemd.time date strings when they're in the past


  • Updates dependencies

5.0.1 - Jan 12, 2022


  • Upgrade clap to version 3 #164

5.0.0 - Nov 14, 2021

New features

  • Secrets can be files for both encoding and decoding #130
  • Support RSASSA-PSS signatures #132
  • [BREAKING] jwt-cli will always validate exp unless you pass --ignore-exp #137
  • Swapped out term-painter for bunt
  • Allow the secret to be base64 encoded #144
  • Show help if no subcommands are used #146

4.0.0 - Feb 16, 2021

New features

  • [BREAKING] Remove the prn option as it's not included in the spec any longer #114
  • [BREAKING] Avoid adding an exp claim automatically. Instead, the --exp flag must be present, with or without a value
  • Support adding jti when encoding
  • Add no-iat flag to disable automatic iat claim generation
  • Add an --iso8601 flag to represent date-based claims as ISO 8601 date strings. Only applies to iat, exp, and nbf

Bug fixes

  • Trim whitespace around a jwt before encoding #120

3.3.0 - Dec 24, 2020

3.2.1 - Sep 13, 2020

3.2.0 - Sep 11, 2020

New features

  • When piping the output of jwt to another command, jwt won't add a trailing newline

Bug fixes

  • When verifying token without an exp claim, jwt won't print that the jwt is inavalid

3.1.0 - Apr 17, 2020

New features

  • Durations (exp, and nbf) can now be set with relative times #68

3.0.1 - Mar 14, 2020

3.0.0 - Mar 14, 2020

New features

  • Updated jsonweboken to version 7, which now allows PEM secrets to be used
    • This requires the filename to end with .pem to be detected correctly

2.5.2 - Feb 02, 2020

Bug fixes

  • Prevent invalid JWT tokens from causing a panic #52

2.5.1 - Oct 07, 2019

Bug fixes

  • 2.5.1 fixes a nasty bug where non-string JSON values would be dropped during encoding

2.5.0 - May 30, 2019

New features

  • Add support for ECDSA algorithms. For now, only ES256 and ES384 are supported. #12

2.4.0 - Apr 20, 2019

New features

  • Add support for stdin on encode and decode. Instead of passing a JSON body or a JWT token, you can simply pass -. #10

Minor changes

  • Updated the project to use rust 2018 edition
  • Update dependencies

2.3.0 - Jan 10, 2019

New features

  • Adds the ability to include a private/public key from a file on the local filesystem using the @ shorthand #9

2.2.1 - Nov 28, 2018

Bug fixes

  • Add a missing > to Aaron's entry in the contributors section of Cargo.toml

2.2.0 - Nov 18, 2018

Minor changes

  • You can now use a fully qualified and valid JSON string as the entire payload body. Add it to the end of the command without a flag to use it. It can be combined with the -P and --payload flags to enhance a JSON string.

2.1.0 - Sep 25, 2018


Minor changes

  • A new output format has been added: JSON! Use the --json or -j flags to output a pure JSON representation of the header and payload, which can be piped into other programs like jq [#6]

2.0.0 - Apr 28, 2018



Breaking (maybe) changes

  • Updated to jsonwebtoken version 4
  • JWTs without the typ header can now be decoded

1.2.0 - Sep 06, 2017

v1.2.0 - Sep 05, 2017

Better stdout and stderr interop

Minor changes

  • Errors are now printed to STDERR instead of STDOUT
  • Proper exit codes should now be emitted. 0 for successes, 1 for failures.
  • The output from the encode command is now just the token, which can be piped or stored in a shell

1.1.0 - Jul 14, 2017



The decoding and validation release!

New features

  • If the JWT you're decoding is invalid, it will still print out the head and claims objects
  • Error messages are now red and bold for better visibility
  • Secret is no longer required for decoding a JWT, but will be validated if one is provided
  • Added info on how to install the binary through homebrew

Bug fixes

  • The proper version number is now displayed in the help commands (and Cargo.toml file)

1.0.0 - Jul 04, 2017



The 1.0 release!

This is the initial non-beta, non-alpha release of jwt-cli!

New features

  • Everything is parsed by serde now. You can pass strings, numbers, arrays, objects, whatever. If serde can parse it, it's valid!

Things left to do

  • Add jwt-cli to package managers!

0.9.1 - Jul 04, 2017



The forkless release!

Bug fixes

  • Swaps out my fork of jsonwebtoken for the master branch of keats' jsonwebtoken
  • Pre-built binaries should start flowing into github again

Roadmap to 1.0

  • Allow for json payload items via -P this=json(['arbitrary', 'data'])

v0.9.0 - Jul 04, 2017

The iat and exp release!

Breaking changes

  • iat is now automatically added to the claims object
  • exp is now automatically added to the claims object if not passed in directly
  • exp defaults to 30 minutes from the time of creation

Bug fixes

  • exp and nbf are now parsed as numbers, not string

Temporary changes

  • Moves to my instance of jsonwebtoken until some PRs are merged

Roadmap to 1.0

  • Allow for json payload items via -P this=json(['arbitrary', 'data'])

v0.8.1 - Jul 03, 2017



Bug fixes

  • Fix tests so that they pass

v0.8.0 - Jul 03, 2017



Dependency updates

Breaking changes

  • Swaps out rustc_serialize for serde
  • Updates jsonwebtoken from version 1 to version 2. This allows for much more precise errors, and expands potential for validation.

Roadmap to 1.0

  • Automatically set iat and exp
  • Default exp to 30 minutes from now
  • Allow for json payload items via `-P this=json(['arbitrary', 'data'])

0.7.0 - Mar 18, 2017



The whoopsies release!

While actually using the project, I found that payload claims were being nested into a root key. Whoops!

Breaking changes

  • The generate command is now encode

New features

  • When decoding, the algorithm option is no longer required (defaults to HS256)
  • Updated to rust 1.16

Bug fixes

  • Payload claims are no longer nested in a _field0 key

Roadmap to 1.0.0

  • Automatically set iat and exp
  • Default exp to 30 minutes from now
  • Swap out rustc_serialize for serde
  • These are all blocked by keats/rust-jwt#19 :(
  • Testing on Windows and Linux

0.6.0 - Mar 13, 2017



The rename release!

Breaking changes

  • Renamed the release binary to jwt. During development, either jwt or jwt-cli is available.

Roadmap to 1.0.0

  • Testing on linux & windows (this was developed on macOS)
  • Work on releasing 1.0.0 to homebrew and chocolatey.

Information - Updated May 09, 2022

Stars: 554
Forks: 40
Issues: 12



A Rust library and command line tool to harden Electron binaries against runtime behavior modifications


This is a Rust command line tool that calculates a histogram of the separate types...

This is a Rust command line tool that calculates a histogram of the separate types of JSON records in an input JSON log file (one...

This is a Rust command line tool that calculates a histogram of the separate types...


is a python module, Rust crate and command line utility for managing current device information that is stored in many CMSIS PACKs


Find all your notes with one command!

Todo_r is a simple rust command line utility that keeps track of your todo items in code

Find all your notes with one command!

A Rust command line utility tool to connect to the QuanticTelecom captive portal

So far, the only mode supported so far requires providing password and login

A Rust command line utility tool to connect to the QuanticTelecom captive portal

Rust Command Line Experiment

This is just a little learning exercise on how to write a command line application in rust and manipulate the

Rust Command Line Experiment

Rust command-line program to automatically RSVP new Meetup events

I still haven't gotten meetup's API to respond and haven't heard back from Meetup

Rust command-line program to automatically RSVP new Meetup events

ImageMapper is a Rust command line tool for mapping/synchronizing a directory structure into a new...

ImageMapper is a Rust command line tool for mapping/synchronizing a directory structure into a new structure with the following properties:

ImageMapper is a Rust command line tool for mapping/synchronizing a directory structure into a new...
Facebook Instagram Twitter GitHub Dribbble