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 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. |
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)://<em>HOSTNAME</em>/api/v3/app" \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer YOUR_JWT"
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.
#!/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}")
#!/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.
#!/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 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