Decode JSON Web Token on the Command Line

As a developer I will come across JSON Web Tokens (JWTs) all the time. In many cases during development and issue resolution I will need to know, what information is contained within the token (header and payload).

Since the token will contain private information, I am not comfortable using online tools to decode the token. Luckily this can easily be accomplished on the Command Line with help of OpenSSL. Let's have a look how it is done on macOS.

Obtain test token

For testing purposes, I use a token from jtw.io.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

JWT contains three parts, separated by dots.

Zsh function time

I am using zsh as my shell, so all I need to do, is add a new function to my .zshrc:

function jwt() {
  for part in 1 2; do
    b64="$(cut -f$part -d. <<< "$1" | tr '_-' '/+')"
    len=${#b64}
    n=$((len % 4))
    if [[ 2 -eq n ]]; then
      b64="${b64}=="
    elif [[ 3 -eq n ]]; then
      b64="${b64}="
    fi
    d="$(openssl enc -base64 -d -A <<< "$b64")"
    python -mjson.tool <<< "$d"
    # don't decode further if this is an encrypted JWT (JWE)
    if [[ 1 -eq part ]] && grep '"enc":' <<< "$d" >/dev/null ; then
        exit 0
    fi
  done
}

What happens is basically this:

  • Split the token by the delimiting . characters.
  • Pad the individual Base64 encoded string (part) so that OpenSSL can read it properly.
  • Base64 decode each part with OpenSSL.
  • Pretty-print with Python's json.tool. The default Python is sufficient here, no need to install anything.

Decode!

To decode, I will start a new shell, and run the function with the token as an argument (Remember to add the quotes):

jwt "eyJ..."

This will output the Header and Payload in a nice and easily readable format:

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

And just like that, I can see what is contained within the token, and I can continue with the task I was actually doing.

Further Reading and inspiration