Сведения о веб-токенах JSON (JWTs)
Для проверки подлинности в качестве приложения или создания маркера доступа к установке необходимо создать веб-токен JSON (JWT). Если для конечной точки REST API требуется JWT, документация по этой конечной точке указывает, что для доступа к конечной точке необходимо использовать JWT.
JWT должен быть подписан с помощью алгоритма RS256
и должен содержать следующие утверждения.
Утверждение | Значение | Сведения |
---|---|---|
iat | Выдано в | Время создания JWT. Чтобы защититься от смещения часов, рекомендуется задать этот 60 секунд в прошлом и убедиться, что дата и время сервера заданы точно (например, с помощью протокола сетевого времени). |
exp | Истекает в | Время истечения срока действия JWT, после которого его нельзя использовать для запроса маркера установки. Время должно быть не более 10 минут в будущем. |
iss | Издатель | Идентификатор клиента идентификатор приложения GitHub App. Это значение используется для поиска правильного открытого ключа для проверки подписи JWT. Идентификатор приложения можно найти на странице параметров для GitHub App. Дополнительные сведения о переходе на страницу параметров для GitHub Appсм. в разделе "Изменение регистрации приложения GitHub". |
alg | Алгоритм кода проверки подлинности сообщений | Это должно быть RS256 так, так как JWT должен быть подписан с помощью алгоритма RS256 . |
Чтобы использовать JWT, передайте его в заголовке Authorization
запроса API. Например:
curl --request GET \
--url "http(s)://HOSTNAME/api/v3/app" \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer YOUR_JWT" \
--header "X-GitHub-Api-Version: 2022-11-28"
В большинстве случаев передать маркер с помощью Authorization: Bearer
или Authorization: token
. Однако при передаче веб-токена JSON (JWT) необходимо использовать Authorization: Bearer
.
Создание веб-маркера JSON (JWT)
Большинство языков программирования имеют пакет, который может создать JWT. Во всех случаях у вас должен быть закрытый ключ и идентификатор данных GitHub App. Дополнительные сведения о создании закрытого ключа см. в разделе "Управление закрытыми ключами для приложений GitHub". Идентификатор приложения можно найти с конечной GET /app
точкой REST API. Дополнительные сведения см. в разделе "Приложения" в документации по REST API.
Note
Вместо создания JWT можно использовать пакеты SDK octokit %}для проверки подлинности в качестве приложения с помощью GitHub. Пакет SDK позаботится о создании JWT для вас и повторно создаст JWT после истечения срока действия маркера. Дополнительные сведения см. в статье "Скриптирование с помощью REST API и JavaScript".
Пример. Создание JWT с помощью Ruby
Note
Чтобы использовать этот скрипт, необходимо выполнить установку gem install jwt
jwt
пакета.
В следующем примере замените YOUR_PATH_TO_PEM
путь к файлу, в котором хранится закрытый ключ. Замените YOUR_APP_ID
идентификатором приложения. Не забудьте заключить значения для YOUR_PATH_TO_PEM
YOUR_APP_ID
и в двойные кавычки.
require 'openssl'
require 'jwt' # https://rubygems.org/gems/jwt
# Private key contents
private_pem = File.read("YOUR_PATH_TO_PEM")
private_key = OpenSSL::PKey::RSA.new(private_pem)
# Generate the JWT
payload = {
# issued at time, 60 seconds in the past to allow for clock drift
iat: Time.now.to_i - 60,
# JWT expiration time (10 minute maximum)
exp: Time.now.to_i + (10 * 60),
# GitHub App's app ID
iss: "YOUR_APP_ID"
}
jwt = JWT.encode(payload, private_key, "RS256")
puts jwt
Пример. Создание JWT с помощью Python
Note
Чтобы использовать этот скрипт, необходимо выполнить установку pip install PyJWT
PyJWT
пакета.
#!/usr/bin/env python3 import sys import time import jwt # Get PEM file path if len(sys.argv) > 1: pem = sys.argv[1] else: pem = input("Enter path of private PEM file: ") # Get the App ID if len(sys.argv) > 2: app_id = sys.argv[2] else: app_id = input("Enter your APP ID: ") # Open PEM with open(pem, 'rb') as pem_file: signing_key = pem_file.read() payload = { # Issued at time 'iat': int(time.time()), # JWT expiration time (10 minutes maximum) 'exp': int(time.time()) + 600, # GitHub App's app ID 'iss': app_id } # Create JWT encoded_jwt = jwt.encode(payload, signing_key, algorithm='RS256') print(f"JWT: {encoded_jwt}")
#!/usr/bin/env python3
import sys
import time
import jwt
# Get PEM file path
if len(sys.argv) > 1:
pem = sys.argv[1]
else:
pem = input("Enter path of private PEM file: ")
# Get the App ID
if len(sys.argv) > 2:
app_id = sys.argv[2]
else:
app_id = input("Enter your APP ID: ")
# Open PEM
with open(pem, 'rb') as pem_file:
signing_key = pem_file.read()
payload = {
# Issued at time
'iat': int(time.time()),
# JWT expiration time (10 minutes maximum)
'exp': int(time.time()) + 600,
# GitHub App's app ID
'iss': app_id
}
# Create JWT
encoded_jwt = jwt.encode(payload, signing_key, algorithm='RS256')
print(f"JWT: {encoded_jwt}")
Этот скрипт предложит вам путь к файлу, в котором хранится закрытый ключ и идентификатор приложения. Кроме того, эти значения можно передать как встроенные аргументы при выполнении скрипта.
Пример. Создание JWT с помощью Bash
Note
Необходимо передать App ID и путь к файлу, в котором хранится закрытый ключ в качестве аргументов при запуске этого скрипта.
#!/usr/bin/env bash set -o pipefail app_id=$1 # App ID as first argument pem=$( cat $2 ) # file path of the private key as second argument now=$(date +%s) iat=$((${now} - 60)) # Issues 60 seconds in the past exp=$((${now} + 600)) # Expires 10 minutes in the future b64enc() { openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n'; } header_json='{ "typ":"JWT", "alg":"RS256" }' # Header encode header=$( echo -n "${header_json}" | b64enc ) payload_json="{ \"iat\":${iat}, \"exp\":${exp}, \"iss\":\"${app_id}\" }" # Payload encode payload=$( echo -n "${payload_json}" | b64enc ) # Signature header_payload="${header}"."${payload}" signature=$( openssl dgst -sha256 -sign <(echo -n "${pem}") \ <(echo -n "${header_payload}") | b64enc ) # Create JWT JWT="${header_payload}"."${signature}" printf '%s\n' "JWT: $JWT"
#!/usr/bin/env bash
set -o pipefail
app_id=$1 # App ID as first argument
pem=$( cat $2 ) # file path of the private key as second argument
now=$(date +%s)
iat=$((${now} - 60)) # Issues 60 seconds in the past
exp=$((${now} + 600)) # Expires 10 minutes in the future
b64enc() { openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n'; }
header_json='{
"typ":"JWT",
"alg":"RS256"
}'
# Header encode
header=$( echo -n "${header_json}" | b64enc )
payload_json="{
\"iat\":${iat},
\"exp\":${exp},
\"iss\":\"${app_id}\"
}"
# Payload encode
payload=$( echo -n "${payload_json}" | b64enc )
# Signature
header_payload="${header}"."${payload}"
signature=$(
openssl dgst -sha256 -sign <(echo -n "${pem}") \
<(echo -n "${header_payload}") | b64enc
)
# Create JWT
JWT="${header_payload}"."${signature}"
printf '%s\n' "JWT: $JWT"
Пример. Создание JWT с помощью PowerShell
В следующем примере замените YOUR_PATH_TO_PEM
путь к файлу, в котором хранится закрытый ключ. Замените YOUR_APP_ID
идентификатором приложения. Обязательно заключите значения YOUR_PATH_TO_PEM
в двойные кавычки.
#!/usr/bin/env pwsh $app_id = YOUR_APP_ID $private_key_path = "YOUR_PATH_TO_PEM" $header = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes((ConvertTo-Json -InputObject @{ alg = "RS256" typ = "JWT" }))).TrimEnd('=').Replace('+', '-').Replace('/', '_'); $payload = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes((ConvertTo-Json -InputObject @{ iat = [System.DateTimeOffset]::UtcNow.AddSeconds(-10).ToUnixTimeSeconds() exp = [System.DateTimeOffset]::UtcNow.AddMinutes(10).ToUnixTimeSeconds() iss = $app_id }))).TrimEnd('=').Replace('+', '-').Replace('/', '_'); $rsa = [System.Security.Cryptography.RSA]::Create() $rsa.ImportFromPem((Get-Content $private_key_path -Raw)) $signature = [Convert]::ToBase64String($rsa.SignData([System.Text.Encoding]::UTF8.GetBytes("$header.$payload"), [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)).TrimEnd('=').Replace('+', '-').Replace('/', '_') $jwt = "$header.$payload.$signature" Write-Host $jwt
#!/usr/bin/env pwsh
$app_id = YOUR_APP_ID
$private_key_path = "YOUR_PATH_TO_PEM"
$header = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes((ConvertTo-Json -InputObject @{
alg = "RS256"
typ = "JWT"
}))).TrimEnd('=').Replace('+', '-').Replace('/', '_');
$payload = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes((ConvertTo-Json -InputObject @{
iat = [System.DateTimeOffset]::UtcNow.AddSeconds(-10).ToUnixTimeSeconds()
exp = [System.DateTimeOffset]::UtcNow.AddMinutes(10).ToUnixTimeSeconds()
iss = $app_id
}))).TrimEnd('=').Replace('+', '-').Replace('/', '_');
$rsa = [System.Security.Cryptography.RSA]::Create()
$rsa.ImportFromPem((Get-Content $private_key_path -Raw))
$signature = [Convert]::ToBase64String($rsa.SignData([System.Text.Encoding]::UTF8.GetBytes("$header.$payload"), [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)).TrimEnd('=').Replace('+', '-').Replace('/', '_')
$jwt = "$header.$payload.$signature"
Write-Host $jwt