Skip to main content

Создание веб-маркера JSON (JWT) для приложения GitHub

Узнайте, как создать веб-токен JSON (JWT) для проверки подлинности в определенных конечных точках REST API с помощью GitHub App.

Сведения о веб-токенах JSON (JWTs)

Для проверки подлинности в качестве приложения или создания маркера доступа к установке необходимо создать веб-токен JSON (JWT). Если для конечной точки REST API требуется JWT, документация по этой конечной точке указывает, что для доступа к конечной точке необходимо использовать JWT.

JWT должен быть подписан с помощью алгоритма RS256 и должен содержать следующие утверждения.

УтверждениеЗначениеСведения
iatВыдано вВремя создания JWT. Чтобы защититься от смещения часов, рекомендуется задать этот 60 секунд в прошлом и убедиться, что дата и время сервера заданы точно (например, с помощью протокола сетевого времени).
expИстекает вВремя истечения срока действия JWT, после которого его нельзя использовать для запроса маркера установки. Время должно быть не более 10 минут в будущем.
issИздательИдентификатор данных GitHub App. Это значение используется для поиска правильного открытого ключа для проверки подписи JWT. Идентификатор приложения можно найти с конечной GET /app точкой REST API. Дополнительные сведения см. в разделе "Приложения" в документации по REST API.
algАлгоритм кода проверки подлинности сообщенийЭто должно быть RS256 так, так как JWT должен быть подписан с помощью алгоритма RS256 .

Чтобы использовать JWT, передайте его в заголовке Authorization запроса API. Например:

curl --request GET \
--url "https://api.github.com/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.

Примечание. Вместо создания JWT можно использовать GitHubдля проверки подлинности в качестве приложения. Пакет SDK позаботится о создании JWT для вас и повторно создаст JWT после истечения срока действия маркера. Дополнительные сведения см. в статье "Скриптирование с помощью REST API и JavaScript".

Пример. Создание JWT с помощью Ruby

Примечание. Чтобы использовать этот скрипт, необходимо выполнить установку 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 identifier
  iss: "YOUR_APP_ID"
}

jwt = JWT.encode(payload, private_key, "RS256")
puts jwt

Пример. Создание JWT с помощью Python

Примечание. Чтобы использовать этот скрипт, необходимо выполнить установку pip install jwt jwt пакета.

Python
#!/usr/bin/env python3
from jwt import JWT, jwk_from_pem
import time
import sys

# 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 = jwk_from_pem(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 identifier
    'iss': app_id
}

# Create JWT
jwt_instance = JWT()
encoded_jwt = jwt_instance.encode(payload, signing_key, alg='RS256')

print(f"JWT:  {encoded_jwt}")

Этот скрипт предложит вам путь к файлу, в котором хранится закрытый ключ и идентификатор приложения. Кроме того, эти значения можно передать как встроенные аргументы при выполнении скрипта.

Пример. Создание JWT с помощью Bash

Примечание. При выполнении этого скрипта необходимо передать идентификатор приложения и путь к файлу, в котором хранится закрытый ключ.

Bash
#!/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 в двойные кавычки.

PowerShell
#!/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