Skip to main content

Generación de un JSON Web Token (JWT) para una aplicación de GitHub

Aprende a crear un JSON Web Token (JWT) para autenticarte en determinados puntos de conexión de API REST con tu GitHub App.

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ónSignificadoDetalles
iatEmitido a lasLa 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).
expExpira a lasLa 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.
issEmisorId. de tu GitHub App. Este valor se usa para buscar la clave pública correcta para comprobar la firma del JWT. 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 de REST.
algAlgoritmo de código de autenticación de mensajesDeberí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 de REST.

Nota: 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 de REST y JavaScript".

Ejemplo: Uso de Ruby para generar un JWT

Nota: 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 identifier
  iss: "YOUR_APP_ID"
}

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

Ejemplo: Uso de Python para generar un JWT

Nota: Debes ejecutar pip install jwt para instalar el paquete jwt para poder usar este 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}")

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

Nota: debes pasar el identificador de la aplicación y la ruta de acceso del archivo donde se almacena la clave privada como argumentos al ejecutar este 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"

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. Reemplaza YOUR_APP_ID por el identificador de la aplicación. Asegúrese de poner los valores para YOUR_PATH_TO_PEM entre comillas dobles.

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