Sobre JWTs (Tokens Web JSON)
Para se autenticar como um aplicativo ou gerar um token de acesso de instalação, você deve gerar um JWT (Token Web JSON). Se um ponto de extremidade da API REST exigir um JWT, a documentação desse ponto indicará que você deve usar um JWT para acessá-lo.
O JWT precisa ser assinado com o algoritmo RS256
e conter as declarações a seguir.
Declaração | Significado | Detalhes |
---|---|---|
iat | Emitido em | A hora em que o JWT foi criado. Para proteção contra descompasso do relógio, recomendamos que você defina esses 60 segundos no passado e verifique se a data e a hora do servidor estão definidas com precisão (por exemplo, usando o protocolo NTP). |
exp | Expira em | A hora de expiração do JWT, após a qual ele não poderá ser usado para solicitar um token de instalação. O tempo não pode ser mais do que dez minutos no futuro. |
iss | Emissor | A ID do aplicativo do seu GitHub App. Esse valor é usado para encontrar a chave pública certa para verificar a assinatura do JWT. Você pode encontrar a ID do seu aplicativo na página de configurações do seu GitHub App. Para obter mais informações sobre como navegar até a página de configurações do GitHub App, consulte "Modificar um registro do Aplicativo GitHub". |
alg | Algoritmo de código de autenticação de mensagem | Deve ser RS256 porque o JWT deve ser assinado usando o algoritmo RS256 . |
Para usar um JWT, passe-o no cabeçalho Authorization
de uma solicitação de API. Por exemplo:
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"
Na maioria dos casos, você pode usar Authorization: Bearer
ou Authorization: token
a fim de passar um token. No entanto, se estiver passando um JWT (token Web JSON), você deverá usar Authorization: Bearer
.
Como gerar um JWT (Token Web JSON)
A maioria das linguagens de programação tem um pacote que pode gerar um JWT. Em todos os casos, você deve ter uma chave privada e a ID dos dados do GitHub App. Para obter mais informações sobre como gerar uma chave privada, confira "Como gerenciar chaves privadas para Aplicativos GitHub". Você pode encontrar a ID do aplicativo com o ponto de extremidade da API REST GET /app
. Para obter mais informações, consulte "Aplicativos" na documentação da API REST.
Note
Em vez de criar um JWT, você pode usar os SDKs do Octokit do GitHub para se autenticar como um aplicativo. O SDK cuidará da geração de um JWT para você e regenerará o JWT assim que o token expirar. Para obter mais informações, confira "Scripts com a API REST e o JavaScript".
Exemplo: usar Ruby para gerar um JWT
Note
Você precisa executar gem install jwt
para instalar o pacote jwt
e usar esse script.
No exemplo a seguir, substitua YOUR_PATH_TO_PEM
pelo caminho do arquivo em que a chave privada está armazenada. Substitua YOUR_APP_ID
pela ID do aplicativo. Inclua os valores de YOUR_PATH_TO_PEM
e YOUR_APP_ID
entre aspas duplas.
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
Exemplo: usar Python para gerar um JWT
Note
Você precisa executar pip install PyJWT
para instalar o pacote PyJWT
e usar esse script.
#!/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}")
Esse script solicitará o caminho do arquivo em que sua chave privada está armazenada e para a ID do aplicativo. Como alternativa, você pode passar esses valores como argumentos embutidos ao executar o script.
Exemplo: usar Bash para gerar um JWT
Note
Você precisa transmitir sua ID do aplicativo e o caminho do arquivo em que a sua chave privada é armazenada como argumentos ao executar esse script.
#!/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"
Por exemplo: como usar o PowerShell para gerar um JWT
No exemplo a seguir, substitua YOUR_PATH_TO_PEM
pelo caminho do arquivo em que a chave privada está armazenada. Substitua YOUR_APP_ID
pela ID do seu aplicativo. Inclua os valores para YOUR_PATH_TO_PEM
entre aspas duplas.
#!/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