Skip to content

Instantly share code, notes, and snippets.

@carestad
Last active August 24, 2023 10:31
Show Gist options
  • Save carestad/bed9cb8140d28fe05e67e15f667d98ad to your computer and use it in GitHub Desktop.
Save carestad/bed9cb8140d28fe05e67e15f667d98ad to your computer and use it in GitHub Desktop.
Script to generate JWT for use with Github apps
#!/usr/bin/env bash
# Generate JWT for Github App
#
# Inspired by implementation by Will Haley at:
# http://willhaley.com/blog/generate-jwt-with-bash/
# From:
# https://stackoverflow.com/questions/46657001/how-do-you-create-an-rs256-jwt-assertion-with-bash-shell-scripting
thisdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
set -o pipefail
# Change these variables:
app_id=1337
app_private_key="$(< $thisdir/app.key)"
# Shared content to use as template
header='{
"alg": "RS256",
"typ": "JWT"
}'
payload_template='{}'
build_payload() {
jq -c \
--arg iat_str "$(date +%s)" \
--arg app_id "${app_id}" \
'
($iat_str | tonumber) as $iat
| .iat = $iat
| .exp = ($iat + 300)
| .iss = ($app_id | tonumber)
' <<< "${payload_template}" | tr -d '\n'
}
b64enc() { openssl enc -base64 -A | tr '+/' '-_' | tr -d '='; }
json() { jq -c . | LC_CTYPE=C tr -d '\n'; }
rs256_sign() { openssl dgst -binary -sha256 -sign <(printf '%s\n' "$1"); }
sign() {
local algo payload sig
algo=${1:-RS256}; algo=${algo^^}
payload=$(build_payload) || return
signed_content="$(json <<<"$header" | b64enc).$(json <<<"$payload" | b64enc)"
sig=$(printf %s "$signed_content" | rs256_sign "$app_private_key" | b64enc)
printf '%s.%s\n' "${signed_content}" "${sig}"
}
sign
@michaelsync
Copy link

I figure it out. The JWT is "${signed_content}"."${sig}"

Thanks.

@carestad
Copy link
Author

carestad commented Dec 9, 2020

Thanks. Where do you get "generated_jwt"? I don't see it in your script. Is "generated_jwt" as same as ${sig}?

I am trying to find out which one is the JWT token. Is it "${sig} or Is it "${signed_content}"."${sig}"?

I see you figured it out, @michaelsync. $generated_jwt is basically the output of the entire script there. I will update my previous response so it is more clear 👍

@thiago-scherrer
Copy link

It helped me a lot. THX!

@kapcod
Copy link

kapcod commented Nov 1, 2021

Thanks! Works great. Strange that Gihub doesn't give bash script as official example, only Ruby.

@samsen1
Copy link

samsen1 commented Nov 17, 2021

Jesus - finally. Went in circles looking for a solution but this one works.

@vibin
Copy link

vibin commented Feb 15, 2023

Just wanted to say thanks for this. Very helpful!

@fernandoc83
Copy link

Thanks a lot, I tried with several methods to create this token without lucky until I used this method.

@89pleasure
Copy link

On MacOS i do get the following error:
line 42: ${algo^^}: bad substitution
Any idea why?

@TrueWill
Copy link

@89pleasure I got the same error. I worked around it using an Ubuntu Docker container.

@rushi
Copy link

rushi commented Aug 24, 2023

For others with this problem you will have to upgrade your version of the bash shell. OSX ships with v3, and the latest is v5.

brew install bash
/opt/homebrew/Cellar/bash/5.2.15/bin/bash script.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment