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
@carestad
Copy link
Author

carestad commented Dec 7, 2020

Hi, Thanks for sharing this script.

What do we need to pass to the authorization? I tried as below but both of them didn't work.

Hi, @michaelsync!

That's a fair question. I have been ussing it like this:

#!/bin/bash
generated_jwt=$(./github-app-jwt.sh)
curl -s \
    -H "Authorization: Bearer ${generated_jwt}" \
    -H "Accept: application/vnd.github.machine-man-preview+json" \
    "${github_api_url}"

So from what I can tell both the Authorization and Accept headers are different. But I use it to authorize use with a Github App, which might work a bit differently. More info about how to auth as a Gitub app here: https://docs.github.com/en/free-pro-team@latest/developers/apps/authenticating-with-github-apps#authenticating-as-a-github-app

@michaelsync
Copy link

@carestad

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}"?

@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