Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Example for decoding a JWT Payload with your Shell (bash, zsh...)

Setup

Add this to your .profile, .bashrc, .zshrc...

decode_base64_url() {
  local len=$((${#1} % 4))
  local result="$1"
  if [ $len -eq 2 ]; then result="$1"'=='
  elif [ $len -eq 3 ]; then result="$1"'=' 
  fi
  echo "$result" | tr '_-' '/+' | openssl enc -d -base64
}

decode_jwt(){
   decode_base64_url $(echo -n $2 | cut -d "." -f $1) | jq .
}

# Decode JWT header
alias jwth="decode_jwt 1"

# Decode JWT Payload
alias jwtp="decode_jwt 2"

Usage

jwtp eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Output

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}
@mvitz

This comment has been minimized.

Copy link

@mvitz mvitz commented Sep 9, 2016

Hi, thanks for sharing. At least for me (Mac OS X 10.11.6, Bash 4.3.46(1)-release) the argument for base64 has to be -D and not -d.

@chriswhite199

This comment has been minimized.

Copy link

@chriswhite199 chriswhite199 commented Jul 12, 2018

To pretty print the expiration field, amend the jq . to:

# For local tz
jq 'if .exp then (.expStr = (.exp|gmtime|strftime("%Y-%m-%dT%H:%M:%S %Z"))) else . end'

# For UTC
jq 'if .exp then (.expStr = (.exp|todate)) else . end'

Output:

{
  "sub": "user",
  "exp": 1531376297,
  "expStr": "2018-07-12T06:18:17 PST"
}
@lounagen

This comment has been minimized.

Copy link

@lounagen lounagen commented Jan 10, 2019

openssl enc -d -base64 doesn't work out of the box on mac (mocos mojave, LibreSSL 2.6.5 openssl version ) with base64 long lines without carriage-returns.

Handle it to be linux/mac compliant with a dummy test on the base64 command:
base64 -d on linux (or mac with linux base64 tool) and base64 -D on mac

Forked here https://gist.github.com/lounagen/bdcf3e59122e80bae6da114352d0280c

@drwetter

This comment has been minimized.

Copy link

@drwetter drwetter commented Jun 26, 2020

Just found this through $SEARCHENGINE

This is shorter (mapfile is bash-only):

#!/bin/bash

decode_jwt(){
     printf "%s" "$1" | base64 -d 2>/dev/null | jq .
}

mapfile jwt < <(printf "%s" "$1" | tr '.' '\n')
decode_jwt "${jwt[0]}"
echo
decode_jwt "${jwt[1]}"

Putting that into an alias would of course work too.

@stokito

This comment has been minimized.

Copy link

@stokito stokito commented Jun 27, 2020

@a-magdy

This comment has been minimized.

Copy link

@a-magdy a-magdy commented Jul 5, 2020

Thanks for the helpful gist
I've adjusted it a bit

  • used base64 instead of openssl (so I don't have to install it on an alpine docker image)
  • changed the order of arguments in the decode_jwt method, expecting the jwt first, and defaulting the second argument to 2 (as we usually need to decode the body)
_decode_base64_url() {
  local len=$((${#1} % 4))
  local result="$1"
  if [ $len -eq 2 ]; then result="$1"'=='
  elif [ $len -eq 3 ]; then result="$1"'=' 
  fi
  echo "$result" | tr '_-' '/+' | base64 -d
}

# $1 => JWT to decode
# $2 => either 1 for header or 2 for body (default is 2)
decode_jwt() { _decode_base64_url $(echo -n $1 | cut -d "." -f ${2:-2}) | jq .; }

# decodes body (default behaviour)
decode_jwt $MY_JWT
# decodes header
decode_jwt $MY_JWT 1 

Link to the fork: https://gist.github.com/a-magdy/a771f1426043ab4b66b19cc9a652908b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.