-
Notifications
You must be signed in to change notification settings - Fork 0
/
jwt-decode-jq-openssl.sh
executable file
·91 lines (82 loc) · 3.49 KB
/
jwt-decode-jq-openssl.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/bin/sh
# Usage: cat /id_token.txt | jwt-decode.sh --no-verify-sig > jwt_payload.json
# Decode a JWT from stdin and verify it's signature with the JWT issuer public key
# Only RS256 keys are supported for signature check
#
# Put OAuth server public key in PEM format to /var/cache/oauth/$JWT_KID.key.pub.pem
# You must create the folder first
# $ sudo mkdir -p /var/cache/oauth/
# To converted key from JWK to PEM use https://8gwifi.org/jwkconvertfunctions.jsp or https://keytool.online/
# NOTE: For Google you can get the keys in PEM format via https://www.googleapis.com/oauth2/v1/certs
# Decode the keys with decodeURIComponent()
# TODO fetch public key automatically in https://jwt.io/ manner:
# get "kid" field from JWT header
# get "iss" field from JWT header which is the token issuer url e.g. https://accounts.google.com
# add /.well-known/openid-configuration and fetch OIDC discovery e.g. wget https://accounts.google.com/.well-known/openid-configuration
# from the OIDC discovery JSON take jwks_uri e.g. https://www.googleapis.com/oauth2/v3/certs
# in the JWKS find the public key (JWK) which signed the JWT
# convert the JWK to PEM format to make openssl happy
# store the fetched pub key into /var/cache/ and next time check it there first to avoid calls to jwks_uri
# HOW TO USE:
# $ chmod +x jwt-decode.sh
# Parse file:
# $ cat id_token.txt | ./jwt-decode.sh
# if signature check failed then error code will be non-zero
if [ -z $(command -v jq) ]; then
>&2 echo "Error 2: missing jq"
exit 2
fi
if [ -z $(command -v openssl) ]; then
>&2 echo "Error 2: missing openssl-util"
exit 2
fi
decode_base64url()
{
echo "${1}" | tr -- '-_' '+/' | openssl base64 -d -A
}
# read the JWT from stdin and split by comma into three variables
IFS='.' read -r JWT_HEADER_B64URL JWT_PAYLOAD_B64URL JWT_SIGNATURE_B64URL
JWT_PAYLOAD=$(decode_base64url "${JWT_PAYLOAD_B64URL}")
if [ "$1" != "--no-verify-sig" ]; then
# verify signature
JWT_ISS=$(echo "$JWT_PAYLOAD" | jq -r .iss)
JWT_HEADER=$(decode_base64url "$JWT_HEADER_B64URL")
JWT_SIGNATURE=$(decode_base64url "$JWT_SIGNATURE_B64URL")
JWT_ALG=$(echo "$JWT_HEADER" | jq -r .alg)
JWT_KID=$(echo "$JWT_HEADER" | jq -r .kid)
if [ "${JWT_ALG}" = "RS256" ]; then
PUB_KEY_FILE="/var/tmp/oauth/$JWT_KID.key.pub.pem"
if [ ! -f "$PUB_KEY_FILE" ]; then
>&2 echo "No pub key $JWT_KID"
if [ "$JWT_ISS" = "https://accounts.google.com" ]; then
mkdir -p /var/tmp/oauth/
# use old jwks_url which return certs in PEM format
OAUTH_CERTS_URL="https://www.googleapis.com/oauth2/v1/certs"
>&2 echo "Fetch certs $OAUTH_CERTS_URL"
wget $OAUTH_CERTS_URL -q -O /tmp/jwks.json
CERT_FILE="/tmp/$JWT_KID.crt"
jq -r ".$JWT_KID" /tmp/jwks.json > "$CERT_FILE"
rm /tmp/jwks.json
openssl x509 -pubkey -in "$CERT_FILE" -noout > "$PUB_KEY_FILE"
rm "$CERT_FILE"
else
>&2 echo "Error 4: Unable to get public key"
exit 4
fi
fi
SIG_FILE=$(mktemp)
echo -n "$JWT_SIGNATURE" > "${SIG_FILE}"
JWT_BODY=$(echo -n "$JWT_HEADER_B64URL.$JWT_PAYLOAD_B64URL")
JWT_SIG_VERIFY_ERR=$(echo -n "$JWT_BODY" | openssl dgst -sha256 -verify "${PUB_KEY_FILE}" -signature "${SIG_FILE}")
JWT_SIG_VERIFY_CODE=$?
rm "${SIG_FILE}"
if [ ${JWT_SIG_VERIFY_CODE} -ne 0 ]; then
>&2 echo "Error 1: Bad Signature: Code $JWT_SIG_VERIFY_CODE $JWT_SIG_VERIFY_ERR"
exit 1
fi
else
>&2 echo "Error 3: Unsupported signature algorithm $JWT_ALG"
exit 3
fi
fi
echo -n "$JWT_PAYLOAD"