create_jwt.sh Reads a JSON payload and creates a JWT, with or without a signature
decode_jwt.sh Reads a JWT from stdin and decodes as human-readable JSON to stdout
| #!/bin/bash | |
| # create_jwt.sh (c) NGINX, Inc. [v0.3 10-Jul-2019] Liam Crilly <liam.crilly@nginx.com> | |
| # | |
| # This script accepts a JSON claimset (JWT payload) and creates produces a | |
| # JOSE-signed token to stdout using one of the supported signature algorithms. | |
| # | |
| # CHANGELOG | |
| # v0.1 Initial version (hs256 only) | |
| # v0.2 Added support for various hs signature lengths | |
| # v0.3 Checks for expired exp claims, option to specify exp duration | |
| if [ $# -eq 0 ]; then | |
| echo "USAGE: ${0##*/} [-exp <mins>] <alg [secret]> <payload>" | |
| echo " -exp will set or override the exp claim with the specified duration" | |
| echo " alg may be 'none' or 'hs*'" | |
| echo " secret will be used for HMAC (hs*) signature" | |
| echo " payload of '-' will read from stdin" | |
| exit 1 | |
| fi | |
| # Check that jq is installed so we can check/modify the exp claim | |
| # | |
| hash jq 2> /dev/null | |
| if [ $? -ne 0 ]; then | |
| echo "${0##*/}: ERROR: please install 'jq' for 'exp' payload manipulation" | |
| exit | |
| fi | |
| # Command line processing | |
| # | |
| VALIDITY_MINS=0 | |
| if [ "$1" == "-exp" ]; then | |
| VALIDITY_MINS=$2 | |
| shift; shift | |
| fi | |
| case $1 in | |
| "none") | |
| HEADER='{"alg":"none","typ":"JWT"}' | |
| PAYLOAD=$2 | |
| shift | |
| ;; | |
| "hs256"|"hs384"|"hs512") | |
| LENGTH=`echo $1 | awk -F"hs" '{print $2}'` | |
| HEADER="{\"alg\":\"HS$LENGTH\",\"typ\":\"JWT\",\"kid\":\"0001\"}" | |
| SECRET=$2 | |
| shift; shift | |
| ;; | |
| *) | |
| echo "${0##*/}: ERROR: unrecognised or unsupported algorithm, $1" | |
| exit 1 | |
| ;; | |
| esac | |
| if [ "$1" == "-" ]; then | |
| PAYLOAD=$(cat) | |
| else | |
| PAYLOAD=$1 | |
| fi | |
| # Check payload is valid JSON | |
| # | |
| if [ `echo $PAYLOAD | jq -r . 2>&1 | grep -c ^parse` -gt 0 ]; then | |
| echo "${0##*/}: ERROR: JWT payload is invalid (not JSON)" | |
| echo $PAYLOAD | jq . | |
| exit 1 | |
| fi | |
| if [ $VALIDITY_MINS -gt 0 ]; then | |
| # Set/update the exp claim | |
| EXP_CLAIM=`date -v +${VALIDITY_MINS}M +%s` | |
| PAYLOAD=`echo $PAYLOAD | jq ".exp = $EXP_CLAIM"` | |
| else | |
| # Check/warn if exp is in the past | |
| EXP_CLAIM=`echo $PAYLOAD | jq -r .exp` | |
| if [ "$EXP_CLAIM" != "null" ] && [ $EXP_CLAIM -lt `date +%s` ]; then | |
| echo "${0##*/}: WARNING: exp claim is in the past, `date -j -f %s $EXP_CLAIM`" 1>&2 | |
| fi | |
| fi | |
| JWT=`echo -n $HEADER | base64 | tr '+\/' '-_' | tr -d '='`.`echo -n $PAYLOAD | base64 | tr '+\/' '-_' | tr -d '='` | |
| if [ "$LENGTH" != "" ]; then | |
| SIG=`echo -n $JWT | openssl dgst -binary -sha$LENGTH -hmac $SECRET | base64 | tr '+\/' '-_' | tr -d '='` | |
| fi | |
| echo $JWT.$SIG |
| #!/usr/bin/env bash | |
| # | |
| # decode_jwt.sh (c) NGINX, Inc. [v0.5 19-Nov-2018] Liam Crilly <liam.crilly@nginx.com> | |
| # | |
| # This script accepts a JWT on stdin and decodes the header and payload into | |
| # human-readable JSON texts. It does not perform signature validation. | |
| # | |
| # CHANGELOG | |
| # v0.4 [28-Jul-2016] Stable | |
| # v0.5 [19-Nov-2018] Support for multiple JSON-prettifiers, reports on decode failure | |
| if [ $# -gt 0 ]; then | |
| echo "${0##*/}: reads a JWT from stdin and decodes as human-readable JSON to stdout" | |
| exit 1 | |
| fi | |
| for json_cli in "jq -C ." "python -m json.tool"; do | |
| hash ${json_cli%% *} 2> /dev/null # Remove chars beyond space | |
| if [ $? -eq 0 ]; then | |
| DO_JSON=$json_cli | |
| break #for | |
| fi | |
| done | |
| if [ "$DO_JSON" == "" ]; then | |
| echo "${0##*/}: WARNING: please install 'jq' or 'python' for prettified JSON output" | |
| DO_JSON=cat | |
| fi | |
| jwt=$(cat) | |
| for section in `echo -n $jwt | cut -f1-2 -d . | tr '.' ' '`; do | |
| padding="=" | |
| while [ `echo -n "$padding" | wc -c` -lt 4 ]; do | |
| decoded=`echo -n "${section}$padding" | base64 -D` | |
| if [ $? -eq 0 ]; then | |
| # Decoded OK, see if we can prettify the JSON (might need a trailing '}') | |
| echo $decoded | $DO_JSON 2>&1 | grep -ve ^Ex -e ^parse | |
| if [ $? -eq 1 ]; then | |
| echo $decoded} | $DO_JSON 2>&1 | grep -ve ^Ex -e ^parse | |
| fi | |
| # Failed to parse JSON, show what's wrong | |
| if [ $? -eq 1 ]; then | |
| echo "${0##*/}: ERROR parsing JSON" | |
| echo $decoded | |
| echo $decoded} | $DO_JSON | |
| fi | |
| break #while | |
| fi | |
| padding="${padding}=" | |
| done | |
| done |