Tokens de GitHub App: revisa estas cuatro capas del backend
Los tokens de instalación de GitHub App ya se emiten en formato stateless. Comprueba validaciones, secretos, proxies y logs antes de que falle una integración.
4 de octubre de 2026 · Leopoldo Benavente Cadena · 8 min de lectura
GitHub terminó el 2 de octubre de 2026 el despliegue gradual del nuevo formato de los tokens de instalación de GitHub App. Desde ahora, los tokens recién emitidos usan por defecto el formato stateless ghs_APPID_JWT y miden aproximadamente 520 caracteres, frente a los 40 del formato anterior.
El cambio no amplía permisos ni cambia la API que solicita el token. El riesgo está en los supuestos que una integración backend pudo guardar durante años: una columna de 40 caracteres, una expresión regular heredada, un proxy que limita Authorization o una regla de redacción que solo reconoce el patrón antiguo.
No confundas las dos credenciales
Una GitHub App usa un JWT de aplicación para autenticarse como la propia aplicación. Con ese JWT puede solicitar un token de acceso para una instalación concreta. El token de instalación es la credencial que se envía después para actuar con los permisos y repositorios de esa instalación.
La documentación de GitHub sobre autenticación mantiene esta separación: el JWT sirve para autenticarse como la app y el token de instalación para autenticarse como una instalación. También existe un tercer caso, el token de usuario, que no forma parte de este cambio.
El flujo mínimo, usando marcadores y no credenciales reales, queda así:
# El JWT de la app solicita un token para una instalación.
curl --request POST \
--url "https://api.github.com/app/installations/INSTALLATION_ID/access_tokens" \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer $APP_JWT" \
--header "X-GitHub-Api-Version: 2026-03-10"
# El token devuelto actúa como la instalación en las llamadas posteriores.
curl --request GET \
--url "https://api.github.com/installation/repositories" \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer $INSTALLATION_TOKEN" \
--header "X-GitHub-Api-Version: 2026-03-10"La guía oficial para generar un token de instalación confirma el endpoint, la posibilidad de limitar repositorios y permisos dentro de los concedidos a la app, y la expiración de una hora. Nada de eso cambia por el formato stateless.
Qué cambió y qué sigue igual
El anuncio de GitHub indica que el despliegue empezó el 27 de abril y ya terminó. Los tokens nuevos conservan el prefijo ghs_, pero ahora son mucho más largos. Los tokens emitidos antes del cambio siguen funcionando hasta que expiran; no hay que interpretar el despliegue como una revocación instantánea de todos los valores existentes.
La misma comunicación confirma que siguen iguales:
- los permisos efectivos del token;
- el alcance por repositorio;
- la duración de una hora;
- el endpoint REST para solicitar tokens de instalación.
Por eso la migración no consiste en cambiar la autorización de la app. Consiste en comprobar que cada componente acepta, transporta, almacena temporalmente y redacta un secreto con el nuevo tamaño sin inspeccionar su estructura interna.
Revisa cuatro capas del backend
1. Validaciones y tipos de datos
Busca comparaciones con longitud exacta 40, expresiones regulares que describan solo el formato anterior, recortes con substring o conversiones que asuman que el valor cabe en un campo pequeño. Revisa también esquemas JSON, validadores de DTO, serializadores, tablas de auditoría y mensajes entre servicios.
El token debe tratarse como una cadena opaca. No lo decodifiques para extraer el app ID, no dependas de supuestos sobre sus segmentos y no uses su longitud o prefijo como validador de producción. La aplicación debe aceptar el secreto que GitHub devuelve y dejar que GitHub determine si es válido, ha expirado o carece de permiso.
Una comprobación de compatibilidad en staging puede verificar que el valor llega a la capa que construye Authorization sin imprimirlo:
token = respuesta_de_github["token"]
assert token is a non-empty string
headers["Authorization"] = "Bearer " + token
respuesta = llamar_a_github(headers)
assert respuesta.status in {200, 201, 204}La aserción no es una política para aceptar tokens en producción ni una invitación a guardar el valor. Su propósito es probar el recorrido completo con un secreto efímero y una respuesta de GitHub.
2. Almacenamiento y configuración
Inspecciona columnas, modelos, variables de entorno y secret stores con límites pequeños. No es necesario persistir un token de instalación: lo habitual es mantenerlo en memoria o en una caché de vida corta y renovarlo antes de su expiración. Si una arquitectura sí lo guarda temporalmente, confirma el tamaño permitido, el cifrado, la rotación y la eliminación al vencer.
No copies el token a tablas de diagnóstico ni a payloads de errores. En una migración, registra únicamente metadatos no sensibles como el ID de instalación, el estado HTTP y la hora de expiración recibida; nunca el secreto ni una captura de la respuesta completa.
3. Proxy, gateway y cliente HTTP
El token viaja en el header Authorization. Comprueba en staging el tamaño máximo de headers configurado en el cliente HTTP, balanceador, gateway, service mesh y servidor de destino. GitHub advierte que una capa puede truncar o rechazar headers largos aunque el código de negocio no tenga una validación de longitud.
La prueba debe recorrer la misma ruta de producción: emisión con el JWT de la app, almacenamiento temporal, salto por proxy y llamada a un endpoint que la instalación tenga permitido. Si falla, conserva el código de estado y los límites configurados, pero redacta el header antes de guardar cualquier log.
No atribuyas el fallo a un proxy concreto sin observar la configuración y una prueba de extremo a extremo. Un 401 indica autenticación ausente, inválida o expirada. Los permisos insuficientes son un problema de autorización y normalmente se revisan como 403, aunque el endpoint puede documentar matices propios. Un 431 o cualquier error de tamaño apunta a los límites de transporte del header. La evidencia debe separar transporte, autenticación y autorización.
4. Logs y redacción
Actualiza las reglas de redacción para que no dependan de una longitud fija ni del único patrón heredado. El objetivo es ocultar cualquier credencial que llegue en Authorization, en una variable de entorno o en una respuesta de error, independientemente de si tiene 40 o aproximadamente 520 caracteres.
Revisa logs de cliente HTTP, trazas distribuidas, eventos de auditoría, excepciones serializadas, colas y herramientas de soporte. Los logs de staging tampoco deben contener tokens reales: usa credenciales efímeras, redacta antes de exportar y comprueba la salida con búsquedas que no revelen el valor.
Prueba ambos formatos antes de retirar el header temporal
El anuncio de mayo sobre el header temporal documenta que X-GitHub-Stateless-S2S-Token se aplica al POST /app/installations/:installation_id/access_tokens y, mientras GitHub lo respeta, admite dos valores deterministas: enabled fuerza un token stateless y disabled fuerza un token clásico opaco. Si se omite, se aplica el despliegue normal; otros valores, como true, false, 1 o 0, se ignoran. GitHub anunció que dejará de respetarlo el 30 de noviembre de 2026 y pide retirarlo del código de producción después de validar ambos formatos.
Si tu integración aún lo usa, limítalo a una configuración explícita de staging y evita que pueda llegar al entorno productivo por defecto. Haz una matriz pequeña:
| Prueba | Qué comprueba | Evidencia que debes conservar |
|---|---|---|
Emisión en staging con X-GitHub-Stateless-S2S-Token: disabled |
Compatibilidad con el formato clásico opaco, mientras el header siga admitido | Respuesta de emisión, llamada autorizada y renovación sin guardar el secreto |
Emisión en staging con X-GitHub-Stateless-S2S-Token: enabled |
Longitud variable, transporte y autorización del formato stateless | Respuesta de emisión, estado HTTP, instalación y repositorio de prueba |
| Token nuevo sin el header temporal | Comportamiento predeterminado posterior al 30 de noviembre | Configuración efectiva del job y llamada autorizada |
| Token expirado | Renovación normal después de una hora | Error controlado, nueva emisión y ausencia del token en logs |
No necesitas construir un token de prueba, conservar una credencial emitida antes del despliegue ni intentar modificar sus caracteres. Solicita ambos formatos de forma determinista desde una instalación de staging mientras el header siga admitido y elimina el header temporal cuando las rutas estén verificadas. El backend no debe distinguirlos mediante una regla de longitud.
Checklist para la revisión
- Confirma qué código genera el JWT de la app y qué código consume el token de instalación; no mezcles sus ciclos de vida.
- Busca validaciones de 40 caracteres, regex del formato antiguo, truncamientos y campos de tamaño fijo.
- Revisa variables de entorno, secret stores, cachés y serializadores que puedan imponer límites pequeños.
- Prueba
Authorizationa través del cliente, proxy, gateway y API de staging con un token stateless real y efímero. - Comprueba que permisos, repositorios y renovación siguen funcionando; no cambies esos controles por una validación local del token.
- Amplía la redacción de logs a cualquier valor de
Authorizationy a respuestas que puedan incluir credenciales. - Retira
X-GitHub-Stateless-S2S-Tokende producción antes del 30 de noviembre de 2026. - Repite la prueba tras actualizar el cliente HTTP o la configuración de infraestructura, porque cualquiera de esas capas puede imponer su propio límite.
El cambio de GitHub es de representación, no de autorización. Si el backend conserva el token como una cadena opaca, evita persistirlo sin necesidad y prueba el trayecto completo, la transición no exige reescribir el modelo de permisos de la app. Exige eliminar supuestos accidentales sobre el tamaño y demostrar que cada capa protege el secreto.
Fuentes primarias
- GitHub Changelog: despliegue de tokens de instalación stateless: fecha del despliegue completo, formato, tamaño aproximado, alcance sin cambios y retirada del header temporal.
- GitHub Changelog: header temporal por solicitud: valores
enabledydisabled, endpoint al que se aplican y pruebas durante la transición. - GitHub Docs: generar un token de acceso de instalación: flujo de emisión, endpoint, permisos, repositorios y expiración.
- GitHub Docs: autenticación con una GitHub App: diferencia entre JWT de aplicación, token de instalación y token de usuario.
Comentarios