Sobre JSON Web Token (JWT)
Para la autenticación como una aplicación o la generación de un token de acceso de instalación, debes generar un JSON Web Token (JWT). Si un punto de conexión de la API de REST necesita un JWT, la documentación de ese punto de conexión indicará que debes usar un JWT para acceder al punto de conexión.
El JWT tiene que estar firmado con el algoritmo RS256
y contener las notificaciones siguientes.
Notificación | Significado | Detalles |
---|---|---|
iat | Emitido a las | La hora a la que se creó el JWT. Para protegerte contra el desfase del reloj, se recomienda establecer estos 60 segundos en el pasado y asegurarse de que la fecha y hora del servidor se establecen con precisión (por ejemplo, mediante el Protocolo de hora de red). |
exp | Expira a las | La hora de expiración del JWT, después de la cual no se puede usar para solicitar un token de instalación. El valor de tiempo debe ser máximo 10 minutos después. |
iss | Emisor | El id. de cliente o id. de aplicación de GitHub App. Este valor se usa para buscar la clave pública correcta para comprobar la firma del JWT. Puedes encontrar el identificador de la aplicacións en la página de configuración de GitHub App. Se recomienda usar el identificador de cliente. Para obtener más información sobre cómo navegar a la página de configuración de GitHub App, consulta Modificación del registro de una instancia de GitHub App. |
alg | Algoritmo de código de autenticación de mensajes | Debería ser RS256 , ya que el JWT debe firmarse mediante el algoritmo RS256 . |
Para usar un JWT, pásalo en el encabezado Authorization
de una solicitud de API. Por ejemplo:
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"
En la mayoría de los casos, puedes usar Authorization: Bearer
o Authorization: token
para pasar un token. Sin embargo, si vas a pasar un token web JSON (JWT), debes usar Authorization: Bearer
.
Generación de un JSON Web Token (JWT)
La mayoría de los lenguajes de programación tienen un paquete que puede generar un JWT. En todos los casos, debes tener una clave privada y el id. de tu GitHub App. Para obtener más información sobre cómo generar una clave privada, consulta Administración de claves privadas para aplicaciones de GitHub. Puedes encontrar el id. de la aplicación con el punto de conexión de la API de REST GET /app
. Para obtener más información, consulta Aplicaciones en la documentación de la API REST.
Note
En vez de crear un JWT, puedes usar los SDK de Octokit de GitHub para autenticarte como aplicación. El SDK se encargará de generar un JWT automáticamente y volverá a generar el JWT una vez que expire el token. Para obtener más información, consulta Scripting con la API REST y JavaScript.
Ejemplo: Uso de Ruby para generar un JWT
Note
Debes ejecutar gem install jwt
para instalar el paquete jwt
para poder usar este script.
En el ejemplo siguiente, reemplaza YOUR_PATH_TO_PEM
por la ruta de acceso del archivo donde se almacena la clave privada. Reemplaza YOUR_APP_ID
por el identificador de la aplicación. Asegúrate de poner los valores YOUR_PATH_TO_PEM
y YOUR_APP_ID
entre comillas dobles.
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 client ID
iss: "YOUR_CLIENT_ID"
}
jwt = JWT.encode(payload, private_key, "RS256")
puts jwt
Ejemplo: Uso de Python para generar un JWT
Note
Debes ejecutar pip install PyJWT
para instalar el paquete PyJWT
para poder usar este 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 Client ID if len(sys.argv) > 2: client_id = sys.argv[2] else: client_id = input("Enter your Client 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 client ID 'iss': client_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 Client ID
if len(sys.argv) > 2:
client_id = sys.argv[2]
else:
client_id = input("Enter your Client 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 client ID
'iss': client_id
}
# Create JWT
encoded_jwt = jwt.encode(payload, signing_key, algorithm='RS256')
print(f"JWT: {encoded_jwt}")
Este script te pedirá la ruta de acceso del archivo donde se almacena la clave privada y el id. de la aplicación. Como alternativa, puedes pasar esos valores como argumentos insertados al ejecutar el script.
Ejemplo: Uso de Bash para generar un JWT
Note
Debes pasar el id. de cliente y la ruta de acceso del archivo donde se almacena la clave privada como argumentos al ejecutar este script.
#!/usr/bin/env bash set -o pipefail client_id=$1 # Client 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\":\"${client_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
client_id=$1 # Client 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\":\"${client_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"
Ejemplo: Uso de PowerShell para generar un JWT
En el ejemplo siguiente, reemplaza YOUR_PATH_TO_PEM
por la ruta de acceso del archivo donde se almacena la clave privada. Reemplace YOUR_CLIENT_ID
por el identificador de la aplicación. Asegúrese de poner los valores para YOUR_PATH_TO_PEM
entre comillas dobles.
#!/usr/bin/env pwsh $client_id = YOUR_CLIENT_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 = $client_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
$client_id = YOUR_CLIENT_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 = $client_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