A command-line tool for JWT, JWS, and JWE

Inspect tokens
from the terminal.

Decode JWTs, verify signatures, and decrypt JWEs with clear, syntax-highlighted output. Everything runs locally, so your tokens never leave your machine.

brew install webcodr/tap/jwtd

jwtd - token inspection

$ jwtd eyJhbGciOiJSUzI1NiIs...

Header:
{
  "alg": "RS256",
  "typ": "JWT"
}

Payload:
{
  "sub": "user_2048",
  "admin": true,
  "iat": "2026-07-22T03:00:00Z (1784689200)",
  "exp": "2026-07-22T04:00:00Z (1784692800)",
  "note": null
}

Signature: eyJfX2p3dGRfXyI...

01 / overview

Focused tools for token inspection.

Decode without a key. Add one when you need signature verification or decrypted content.

01

Decode JWTs

View headers, claims, signatures, and readable timestamps flagged when a token is expired or not yet valid.

02

Verify signatures

Check JWS signatures independently from claim validation.

03

Decrypt JWEs

Inspect protected headers and decrypt compact JWEs with the appropriate key.

04

Inspect nested tokens

Follow JWT and JWE payloads through nested token structures.

05

Use established key formats

Load PEM, DER, certificates, JWKs, encoded keys, or raw secrets.

06

Script with JSON

Emit one machine-readable object with --json for piping into tools like jq.

02 / installation

Install jwtd.

A suitable method is selected for your operating system. All options remain available.

Latest release: v5.1.0

macOS

Homebrew formula

Install the current release from the webcodr tap. Apple silicon and Intel are both covered.

brew install webcodr/tap/jwtd
Prefer a manual binary? Grab a darwin release archive

Linux

Packages for every distribution

Homebrew, native packages, and per-distro repositories are all available. Pick whichever fits your system.

Homebrew — also works on macOS

brew install webcodr/tap/jwtd

Arch Linux — AUR

yay -S jwtd-bin

Fedora / RHEL — COPR

sudo dnf copr enable webcodr/jwtd
sudo dnf install jwtd

Debian / Ubuntu - amd64 Download .deb

curl -fLO https://github.com/webcodr/jwtd/releases/latest/download/jwtd-linux-amd64.deb
sudo dpkg -i jwtd-linux-amd64.deb

Debian / Ubuntu - arm64 Download .deb

curl -fLO https://github.com/webcodr/jwtd/releases/latest/download/jwtd-linux-arm64.deb
sudo dpkg -i jwtd-linux-arm64.deb

Fedora / RHEL / openSUSE - amd64 Download .rpm

curl -fLO https://github.com/webcodr/jwtd/releases/latest/download/jwtd-linux-amd64.rpm
sudo rpm -i jwtd-linux-amd64.rpm

Fedora / RHEL / openSUSE - arm64 Download .rpm

curl -fLO https://github.com/webcodr/jwtd/releases/latest/download/jwtd-linux-arm64.rpm
sudo rpm -i jwtd-linux-arm64.rpm
View all Linux packages and release archives

Windows

Scoop bucket

Add the webcodr bucket once, then install jwtd.

scoop bucket add webcodr https://github.com/webcodr/scoop-bucket
scoop install jwtd
Prefer a manual binary? Grab a windows release archive

macOS / Linux

Nix flake

Install from the flake into your profile, or run it ad hoc with nix run.

nix profile install github:webcodr/jwtd

Go 1.26+

Install from source

Build the latest tagged release with your Go toolchain.

go install github.com/webcodr/jwtd@latest

The Homebrew formula and the .deb / .rpm packages install shell completions for bash, zsh, and fish.

03 / usage

Common workflows.

Pass a token as an argument, pipe it through stdin, or use the interactive prompt.

01

Decode a JWT

View the header, claims, and signature without a key.

jwtd eyJhbGciOiJIUzI1NiIs...
02

Verify a JWS signature

Verify the cryptographic signature without evaluating claims such as expiry. Invalid signatures exit nonzero.

jwtd --key /path/to/public-key.pem eyJhbGciOiJSUzI1NiIs...
03

Decrypt a JWE

Compact JWEs are detected automatically. Provide a private key to decrypt the payload. Nested JWT and JWE payloads are decoded in place.

jwtd --key /path/to/private-key.pem eyJhbGciOiJSU0EtT0FF...
04

Pipe a token from stdin

Read the token from a pipe, so output from other tools flows straight in. Wrapped or spaced tokens are accepted.

pbpaste | jwtd
05

Supply the key from the environment

Set JWTD_KEY instead of passing --key. It accepts the same formats and is overridden by an explicit flag.

JWTD_KEY=/path/to/public-key.pem jwtd eyJhbGciOiJSUzI1NiIs...
06

Use the interactive prompt

Run jwtd with no token and no pipe to enter one at an editable prompt.

jwtd
07

Verify with a raw HMAC secret

Prefix the key with raw: to pass a literal symmetric secret instead of a file, so an HS256 token verifies without touching disk.

jwtd --key raw:my-hmac-secret eyJhbGciOiJIUzI1NiIs...
08

Emit machine-readable JSON

Add --json for a single object per token, with exact numbers and raw timestamps, ready to pipe into jq. Invalid signatures still print and exit nonzero.

jwtd --json eyJhbGciOiJIUzI1NiIs... | jq .payload
09

Control color output

Color auto-disables off a terminal. Use --color to force it, for example through a pager: auto, always, or never.

jwtd --color=always eyJhbGciOiJIUzI1NiIs... | less -R

04 / key formats

Use the key format you have.

The --key flag and JWTD_KEY environment variable use the same format detection.

  • PEMRSA, EC, Ed25519, private or public
  • DERPKCS#1, PKCS#8, SEC 1, PKIX
  • X.509Certificate public keys
  • JWK / JWK SetSingle keys, or the set entry matching the token's kid
  • Base64Standard or URL-safe encoded material
  • hmac:A file of symmetric secret bytes
  • raw:An inline literal symmetric secret

Explicit HMAC secret

jwtd --key raw:my-hmac-secret eyJhbGciOiJIUzI1NiIs...

05 / algorithms

Broad algorithm support.

Signature verification and JWE decryption cover the algorithms defined by the JOSE standards. Accepted signing algorithms are restricted to those matching the key type to rule out algorithm confusion.

JWS signatures

HMAC, RSA (PKCS#1 v1.5 and PSS), ECDSA, and EdDSA.

  • HS256
  • HS384
  • HS512
  • RS256
  • RS384
  • RS512
  • PS256
  • PS384
  • PS512
  • ES256
  • ES384
  • ES512
  • EdDSA

JWE key management

RSA, ECDH-ES, AES key wrap, AES-GCM key wrap, PBES2, and direct.

  • RSA1_5
  • RSA-OAEP
  • RSA-OAEP-256
  • ECDH-ES
  • ECDH-ES+A128KW
  • ECDH-ES+A192KW
  • ECDH-ES+A256KW
  • A128KW
  • A192KW
  • A256KW
  • A128GCMKW
  • A192GCMKW
  • A256GCMKW
  • PBES2-HS256+A128KW
  • PBES2-HS384+A192KW
  • PBES2-HS512+A256KW
  • dir

JWE content encryption

AES-CBC with HMAC and AES-GCM.

  • A128CBC-HS256
  • A192CBC-HS384
  • A256CBC-HS512
  • A128GCM
  • A192GCM
  • A256GCM

06 / release security

Verifiable releases.

Release archives and Linux packages are listed in checksums.txt, which is signed with a keyless Cosign bundle. Each archive also includes a Syft SPDX SBOM.

View verification instructions

Verify checksums.txt

cosign verify-blob \
  --bundle checksums.txt.sigstore.json \
  --certificate-identity-regexp '^https://github.com/webcodr/jwtd/\.github/workflows/release\.yml@' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  checksums.txt

07 / faq

Questions, answered.

What jwtd does, and just as importantly, what it deliberately does not.

Does jwtd send my token anywhere?

No. jwtd runs entirely on your machine and makes no network requests. Decoding, verification, and decryption all happen locally, so the secrets inside a token never leave your terminal.

Does verifying a signature also check expiry?

No. Signature verification reports only whether the cryptographic signature is valid. Claim checks such as expiry are kept separate, so an expired but authentic token still verifies. An invalid signature exits nonzero.

Do I need a key to decode a token?

No. Decoding a JWT and inspecting a JWE protected header need no key. A key is only required to verify a JWS signature or decrypt a JWE payload.

How do I verify an HS256 token with a shared secret?

Pass the secret explicitly: hmac:<file> for a file of secret bytes, or raw:<secret> for an inline one. jwtd never treats an unrecognized key file as a symmetric secret on its own — a public key is a published value, so guessing would let anyone who knows it forge a token that verified.

Can I use an SSH public key?

Not directly. OpenSSH keys, authorized_keys entries, and RFC 4716 armor are detected and reported with a conversion hint. Convert RSA and ECDSA keys with ssh-keygen -e -m PKCS8 -f <key>, then pass the result.

Can I get machine-readable output?

Yes. --json prints one JSON object per token instead of the colored sections: header, payload, and signature, plus signatureValid when a key is given. Numbers are exact and timestamps stay raw, so it pipes cleanly into jq. An invalid signature still prints and exits nonzero.