Сведения о веб-токенах JSON (JWTs)
Для проверки подлинности в качестве приложения или создания маркера доступа к установке необходимо создать веб-токен JSON (JWT). Если для конечной точки REST API требуется JWT, документация по этой конечной точке указывает, что для доступа к конечной точке необходимо использовать JWT.
JWT должен быть подписан с помощью алгоритма RS256
и должен содержать следующие утверждения.
Утверждение | Значение | Сведения |
---|---|---|
iat | Выдано в | Время создания JWT. Чтобы защититься от смещения часов, рекомендуется задать этот 60 секунд в прошлом и убедиться, что дата и время сервера заданы точно (например, с помощью протокола сетевого времени). |
exp | Истекает в | Время истечения срока действия JWT, после которого его нельзя использовать для запроса маркера установки. Время должно быть не более 10 минут в будущем. |
iss | Издатель | Идентификатор клиента client или идентификатор приложения GitHub App. Это значение используется для поиска правильного открытого ключа для проверки подписи JWT. Идентификатор приложенияs можно найти на странице параметров для 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 client ID
iss: "YOUR_CLIENT_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 Client ID if len(sys.argv) > 2: client_id = sys.argv[2] else: client_id = input("Enter your Client 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 client ID 'iss': client_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 Client ID
if len(sys.argv) > 2:
client_id = sys.argv[2]
else:
client_id = input("Enter your Client 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 client ID
'iss': client_id
}
# Create JWT
encoded_jwt = jwt.encode(payload, signing_key, algorithm='RS256')
print(f"JWT: {encoded_jwt}")
Этот скрипт предложит вам путь к файлу, в котором хранится закрытый ключ и идентификатор приложения. Кроме того, эти значения можно передать как встроенные аргументы при выполнении скрипта.
Пример. Создание JWT с помощью Bash
Note
Необходимо передать Client ID и путь к файлу, в котором хранится закрытый ключ в качестве аргументов при запуске этого скрипта.
#!/usr/bin/env bash set -o pipefail client_id=$1 # Client 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\":\"${client_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
client_id=$1 # Client 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\":\"${client_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_CLIENT_ID
идентификатором приложения. Обязательно заключите значения YOUR_PATH_TO_PEM
в двойные кавычки.
#!/usr/bin/env pwsh $client_id = YOUR_CLIENT_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 = $client_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
$client_id = YOUR_CLIENT_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 = $client_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