npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

jwtinfo

v0.7.0

Published

Command line tool to get information about JWTs (Json Web Tokens)

Readme

jwtinfo

build badge codecov crates.io badge API documentation License: MIT

A command line tool to inspect JWTs: decode the header and claims of a signed token (JWS), or decrypt an encrypted token (JWE) using your key.

[!IMPORTANT] The Rust library API is deprecated starting with 0.7.0. jwtinfo is maintained as a CLI tool. Its library parsing/decryption API remains functional but is in maintenance mode, will not gain new features, and may be removed in a future release. See Rust library deprecation for migration guidance. The CLI is not deprecated.

This README follows development on main. Package managers and the installers below provide the latest published release, which may not yet include all changes described here. See the releases and changelog for version-specific changes.

Features

  • Inspect JWS headers and JSON claims without verifying the signature.
  • Decrypt supported JWE tokens with an RSA or symmetric key.
  • Show the payload, headers, or full contents, with optional JSON formatting.
  • Read a token from an argument or stdin and pipe JSON output to other tools.
  • Inspect both headers and the inner claims of a JWE wrapping a JWS.

jwtinfo is an inspection tool: it does not validate JWS signatures, expiry, issuer, or audience. Successful JWE decryption checks its authentication tag, but does not verify the signature or claims of a nested JWS.

Usage

Pass a compact token as an argument, or use - to read it from stdin. Surrounding whitespace is accepted.

token='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
jwtinfo "$token"

The default output is the JSON payload:

{"iat":1516239022,"name":"John Doe","sub":"1234567890"}

Show the header or both the header and claims:

jwtinfo --header "$token"
jwtinfo --full --pretty "$token"

The second command prints:

{
  "claims": {
    "iat": 1516239022,
    "name": "John Doe",
    "sub": "1234567890"
  },
  "header": {
    "alg": "HS256",
    "typ": "JWT"
  }
}

Read a token from a file or use jq to select a claim:

jwtinfo --full --pretty - < token.txt
jwtinfo "$token" | jq -r .name

| Option | Purpose | | --- | --- | | -H, --header | Show the available header(s) | | -F, --full | Show the headers and payload | | -P, --pretty | Pretty-print JSON output | | -K, --key <path> | Read a key file to decrypt a JWE | | -h, --help | Show command-line help | | -V, --version | Show the installed version |

--header and --full are mutually exclusive. Parsing, file-reading, and decryption failures produce an error on stderr and a nonzero exit status. Supplying --key for a JWS prints a warning and continues decoding; it does not verify the signature.

JWE decryption

Provide a key file and a compact encrypted token:

jwtinfo --key /path/to/private.pem - < /path/to/jwe.txt
jwtinfo --key /path/to/private.pem --full --pretty - < /path/to/jwe.txt

Without a key, a JWE produces a placeholder asking for a decryption key. You can still inspect its header:

jwtinfo --header --pretty - < /path/to/jwe.txt

Supported content encryption (enc): A128GCM and A256GCM.

| Key management (alg) | Required key | Accepted formats | | --- | --- | --- | | RSA-OAEP, RSA-OAEP-256 | RSA private key | PKCS#1/PKCS#8 PEM or DER; RSA JWK | | dir | Content-encryption key: 16 bytes for A128GCM, 32 for A256GCM | Raw bytes; oct JWK | | A128KW, A192KW, A256KW | Key-encryption key: 16, 24, or 32 bytes respectively | Raw bytes; oct JWK |

Files of exactly 16, 24, or 32 bytes are always treated as raw symmetric keys, without trimming or text decoding. Other files are checked for PEM, JWK, and DER encodings. A raw file contains the key bytes themselves, not their hexadecimal or base64 text representation; do not append a newline.

Display modes

| Input | Default | --header | --full | | --- | --- | --- | --- | | JWS | JSON claims | Header | {header, claims} | | JWE without a key | JSON placeholder string | JWE header | {header, claims: placeholder} | | Decrypted JWE plaintext | Raw UTF-8 text | JWE header | {header, payload} | | Decrypted JWE with cty: "JWT" and an inner JWS | Inner JSON claims | {jwe_header, jws_header} | {jwe_header, jws_header, claims} |

--pretty formats JSON output. It leaves raw decrypted plaintext unchanged, even if that plaintext happens to contain JSON. In full output, a plaintext JWE payload is a JSON string. The cty: "JWT" header determines whether the decrypted payload is parsed as a nested token.

Limitations

  • JWS inspection expects a base64url-encoded JSON header and JSON payload; it does not support detached or unencoded payloads. Empty signatures, including unsecured JWTs with alg: "none", can be inspected.
  • Decrypted JWE payloads must be UTF-8 text. Binary payloads are not supported.
  • Nested display supports JWE → JWS. A payload marked cty: "JWT" that contains another JWE is rejected; recursive decryption is not implemented.
  • Decryption rejects headers containing zip (compression) or crit (critical extensions). Their headers can still be inspected without a key.
  • RSA1_5, ECDH-ES (including key-wrap variants), PBES2-*, A192GCM, A192GCMKW, and the A128CBC-HS256 / A192CBC-HS384 / A256CBC-HS512 family are unsupported, as are EC and OKP keys.
  • GCMKW interoperability: A128GCMKW / A256GCMKW decryption uses biscuit, which expects the header's iv and tag as JSON byte arrays. The base64url strings required by RFC 7518 §4.7 are rejected with an explicit limitation error. Do not expect standard GCMKW tokens from other JOSE libraries to decrypt.

Install

You can install the binary in several ways:

npm

Install via npm (Node.js package manager):

npm install -g jwtinfo

Or use npx to run without installing:

npx jwtinfo <token>

Homebrew

Install via Homebrew (macOS and Linux):

# Add the tap
brew tap lmammino/tap

# Install jwtinfo
brew install jwtinfo

Or install directly in one command:

brew install lmammino/tap/jwtinfo

Shell Installer (macOS, Linux, WSL)

Download and install precompiled binaries with a single command:

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/lmammino/jwtinfo/releases/latest/download/jwtinfo-installer.sh | sh

PowerShell Installer (Windows)

Download and install precompiled binaries with PowerShell:

irm https://github.com/lmammino/jwtinfo/releases/latest/download/jwtinfo-installer.ps1 | iex

Cargo

You can install the binary in your system with cargo:

cargo install jwtinfo --locked

Precompiled binaries

Pre-compiled binaries for multiple platforms are available in the Releases page.

Using Nix

If you are using Nix, you can install the jwtinfo binary with the following command:

nix profile install github:lmammino/jwtinfo

Or, if you prefer to use a configuration file, you can add the following to your flake:

jwtinfo = {
    url = "github:lmammino/jwtinfo";
    inputs.nixpkgs.follows = "nixpkgs";
};

# ... with home.nix
home.packages = [ inputs.jwtinfo.packages."x86_64-linux".default ];

# ... with configuration.nix
environment.systemPackages = [ inputs.jwtinfo.packages."x86_64-linux".default ];

Make sure to replace "x86_64-linux" with your target platform.

You can also just try it out in a Nix shell with:

nix shell github:lmammino/jwtinfo -c jwtinfo <some_jwt_token>

Finally, for development purposes, you can clone this repo and then run:

nix develop

Alternatives

If you don't want to install a binary for debugging JWT, a super simple bash alternative called jwtinfo.sh is available.

Rust library deprecation

Starting with 0.7.0, the parsing/decryption functions jws::parse, jw_parser::parse_token, jw_parser::parse_jwe, jwe::handle_jwe, and jwe::decrypt_jwe are deprecated. The library remains functional in maintenance mode, but new integrations should use a dedicated JWT library. Consider biscuit, which jwtinfo uses internally, or consult the JWT library directory; check the library's algorithm and validation support for your application.

Version 0.7.0 also breaks the previous library API. Existing consumers should consult the migration details in the changelog and API documentation. In particular:

  • jwt::Token becomes jws::JwsToken; the jwt module becomes jws.
  • jws::parse and JwsToken::from_str accept JWS inputs only. The deprecated jw_parser::parse_token returns a JWToken enum for either JWS or JWE.
  • JWE fields use read-only accessors, and decryption/output signatures and error types have changed.

Installing and using the CLI through Cargo remains supported.

Development

Use a current stable Rust toolchain. CI tests stable Rust; this project does not currently declare a minimum supported Rust version.

cargo build --locked
cargo test --locked
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo fmt --check

To run the local CLI:

cargo run -- --help
cargo run -- --full --pretty - < token.txt

Coverage

CI uses cargo-llvm-cov. For a local HTML report:

rustup component add llvm-tools-preview
cargo install cargo-llvm-cov --locked
cargo llvm-cov --all-features --workspace --html

Open target/llvm-cov/html/index.html. To produce the LCOV report used by CI:

cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info

Releases

Releases are driven by version tags and cargo-dist. The workflow builds binaries and installers, creates a GitHub release, publishes to crates.io and npm, and updates the Homebrew tap. See the release checklist before pushing a tag.

Credits

A special thank you goes to the Rust Reddit community for providing a lot of useful suggestions on how to improve this project. A special thanks goes to: mardiros, matthieum, steveklabnik1, ESBDB, Dushistov, Doddzilla7. Another huge thank you goes to the Rust stackoverflow community, especially to Denys Séguret.

Big thanks also go to Tim McNamara for conducting a live code review of this codebase.

Contributing

Everyone is very welcome to contribute to this project. You can contribute just by submitting bugs or suggesting improvements by opening an issue on GitHub.

License

Licensed under MIT License. © Luciano Mammino & Stefano Abalsamo.