Skip to main content

GitHub 앱에 대한 JWT(JSON Web Token) 생성

GitHub App을(를) 사용하여 특정 REST API 엔드포인트에 인증하는 JWT(JSON Web Token)를 만드는 방법을 알아봅니다.

JWT(JSON Web Token) 정보

앱으로 인증하거나 설치 액세스 토큰을 생성하려면 JWT(JSON Web Token)를 생성해야 합니다. REST API 엔드포인트가 JWT를 필요한 경우 해당 엔드포인트에 대한 설명서에는 JWT를 사용하여 엔드포인트에 액세스해야 함을 나타냅니다.

JWT는 RS256 알고리즘을 사용하여 서명되어야 하며 다음 클레임을 포함해야 합니다.

클레임의미세부 정보
iat발급 시간JWT가 만들어질 시간입니다. 클록 드리프트를 방지하려면 이를 과거 60초로 설정하고 서버의 날짜와 시간을 정확하게 설정하는 것이 좋습니다(예: 네트워크 타임 프로토콜 사용).
exp만료 시간JWT의 만료 시간이며, 그 후에는 설치 토큰을 요청하는 데 사용할 수 없습니다. 시간은 앞으로 10분 이내여야 합니다.
issIssuerGitHub App용 ID입니다. 이 값은 JWT의 서명을 확인하는 데 적합한 공개 키를 찾는 데 사용됩니다. GET /app REST API 엔드포인트를 사용하여 앱의 ID를 찾을 수 있습니다. 자세한 내용은 REST API 설명서에 있는 ""을 참조하세요.
alg메시지 인증 코드 알고리즘이것은 RS256 알고리즘을 사용하여 JWT가 서명되어야 하기 때문에 RS256여야 합니다.

JWT를 사용하려면 API 요청의 Authorization 헤더에 전달합니다. 예시:

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을 사용하여 전달할 수 있습니다. 그러나 JWT(JSON 웹 토큰)를 전달하는 경우 Authorization: Bearer를 사용해야 합니다.

JWT(JSON Web Token) 생성

대부분의 프로그래밍 언어에는 JWT를 생성할 수 있는 패키지가 있습니다. 모든 경우에 GitHub App의 프라이빗 키와 ID가 있어야 합니다. 프라이빗 키 생성에 관한 자세한 내용은 "GitHub 앱에 대한 프라이빗 키 관리"을 참조하세요. GET /app REST API 엔드포인트를 사용하여 앱의 ID를 찾을 수 있습니다. 자세한 내용은 REST API 설명서에 있는 ""을 참조하세요.

참고: JWT를 만드는 대신 GitHub의 Oktokit SDK를 사용하여 앱으로 인증할 수 있습니다. SDK는 JWT 생성을 처리하고 토큰이 만료되면 JWT를 다시 생성합니다. 자세한 내용은 "REST API 및 JavaScript를 사용하여 스크립팅"을 참조하세요.

예: 루비를 사용하여 JWT 생성

참고: 이 스크립트를 사용하려면 jwt 패키지를 설치하기 위해 gem install jwt을(를) 실행해야 합니다.

다음 예제에서는 YOUR_PATH_TO_PEM을(를) 프라이빗 키가 저장된 파일 경로로 바꿉니다. YOUR_APP_ID을(를) 앱의 ID으로 바꿉니다. YOUR_PATH_TO_PEMYOUR_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 생성

참고: 이 스크립트를 사용하려면 jwt 패키지를 설치하기 위해 pip install 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}")

이 스크립트는 프라이빗 키가 저장된 파일 경로와 앱의 ID를 표시합니다. 또는 스크립트를 실행할 때 이러한 값을 인라인 인수로 전달할 수 있습니다.

예제: Bash를 사용하여 JWT 생성

참고: 이 스크립트를 실행할 때 프라이빗 키가 인수로 저장되는 앱 ID와 파일 경로를 전달해야 합니다.

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"

예제: PowerShell을 사용하여 JWT 생성

다음 예제에서는 YOUR_PATH_TO_PEM을(를) 프라이빗 키가 저장된 파일 경로로 바꿉니다. YOUR_APP_ID을(를) 앱의 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