1#!/usr/bin/env bash 2# 3# Request an ACCESS_TOKEN to be used by a GitHub APP 4# Environment variable that need to be set up: 5# * APP_ID, the GitHub's app ID 6# * INSTALL_ID, the Github's app's installation ID 7# * APP_PRIVATE_KEY, the content of GitHub app's private key in PEM format. 8# 9# https://github.com/orgs/community/discussions/24743#discussioncomment-3245300 10# 11 12set -o pipefail 13 14_GITHUB_HOST=${GITHUB_HOST:="github.com"} 15 16# If URL is not github.com then use the enterprise api endpoint 17if [[ ${GITHUB_HOST} = "github.com" ]]; then 18 URI="https://api.${_GITHUB_HOST}" 19else 20 URI="https://${_GITHUB_HOST}/api/v3" 21fi 22 23API_VERSION=v3 24API_HEADER="Accept: application/vnd.github.${API_VERSION}+json" 25CONTENT_LENGTH_HEADER="Content-Length: 0" 26APP_INSTALLATIONS_URI="${URI}/app/installations" 27 28 29# JWT parameters based off 30# https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#authenticating-as-a-github-app 31# 32# JWT token issuance and expiration parameters 33JWT_IAT_DRIFT=60 34JWT_EXP_DELTA=600 35 36JWT_JOSE_HEADER='{ 37 "alg": "RS256", 38 "typ": "JWT" 39}' 40 41 42build_jwt_payload() { 43 now=$(date +%s) 44 iat=$((now - JWT_IAT_DRIFT)) 45 jq -c \ 46 --arg iat_str "${iat}" \ 47 --arg exp_delta_str "${JWT_EXP_DELTA}" \ 48 --arg app_id_str "${APP_ID}" \ 49 ' 50 ($iat_str | tonumber) as $iat 51 | ($exp_delta_str | tonumber) as $exp_delta 52 | ($app_id_str | tonumber) as $app_id 53 | .iat = $iat 54 | .exp = ($iat + $exp_delta) 55 | .iss = $app_id 56 ' <<< "{}" | tr -d '\n' 57} 58 59base64url() { 60 base64 | tr '+/' '-_' | tr -d '=\n' 61} 62 63rs256_sign() { 64 openssl dgst -binary -sha256 -sign <(echo "$1") 65} 66 67request_access_token() { 68 jwt_payload=$(build_jwt_payload) 69 encoded_jwt_parts=$(base64url <<<"${JWT_JOSE_HEADER}").$(base64url <<<"${jwt_payload}") 70 encoded_mac=$(echo -n "$encoded_jwt_parts" | rs256_sign "${APP_PRIVATE_KEY}" | base64url) 71 generated_jwt="${encoded_jwt_parts}.${encoded_mac}" 72 73 auth_header="Authorization: Bearer ${generated_jwt}" 74 75 app_installations_response=$(curl -sX POST \ 76 -H "${auth_header}" \ 77 -H "${API_HEADER}" \ 78 --header "X-GitHub-Api-Version: 2022-11-28" \ 79 --url "https://api.github.com/app/installations/${INSTALL_ID}/access_tokens" \ 80 ) 81 echo "$app_installations_response" | jq --raw-output '.token' 82} 83 84request_access_token 85