Skip to main content

Como gerar um JWT (Token Web JSON) para um Aplicativo GitHub

Saiba como criar um JWT para autenticar determinados pontos de extremidade da API REST com seus GitHub App.

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çãoSignificadoDetalhes
iatEmitido emA 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).
expExpira emA 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.
issEmissorA ID 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 aplicativo com o ponto de extremidade da API REST GET /app. Para obter mais informações, consulte "Aplicativos" na documentação da API REST.
algAlgoritmo de código de autenticação de mensagemDeve 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 "https://api.github.com/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.

Observação: 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

Observação: você deve 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 identifier
  iss: "YOUR_APP_ID"
}

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

Exemplo: usar Python para gerar um JWT

Observação: você deve executar pip install jwt para instalar o pacote jwt e usar esse script.

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}")

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

Observação: você deve passar sua ID do aplicativo e o caminho do arquivo em que sua chave privada é armazenada como argumentos ao executar esse script.

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"

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 aplicativo. Inclua os valores para YOUR_PATH_TO_PEM entre aspas duplas.

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