Volver al cuaderno
IT & Security10 min de lectura

JWT desde cero: para qué sirve, cómo protegerlo e implementarlo con IA

Comprende identidad, firmas y permisos con un caso B2B. Código completo en JavaScript, Python y PHP, tests negativos y prompts en inglés.

¿Para qué me sirve?

Imagina una aplicación móvil de eventos que consulta una API de facturación. Después de iniciar sesión, necesita hacer muchas peticiones sin reenviar la contraseña. Un token de acceso breve transporta una declaración firmada sobre el usuario autenticado. La API la comprueba antes de atender la petición. Es útil para clientes móviles o varios servicios que verifican acceso por separado.

JWT es un formato, no un sistema completo de autenticación. Para una web tradicional, una sesión de servidor con cookie opaca puede ser más sencilla. Ambas opciones necesitan permisos. Al terminar podrás explicar el flujo, ejecutar tres implementaciones equivalentes, rechazar tokens inválidos y pedir a la IA cambios comprobables. El proyecto es un laboratorio local sin un endpoint real de inicio de sesión.

1. Del inicio de sesión a la factura

El sistema fiable autentica al usuario antes de emitir el token. El cliente lo envía por HTTPS, habitualmente en Authorization: Bearer. La API valida firma y declaraciones, y después comprueba el permiso para esa factura concreta.

Nuestro usuario ficticio user-7 pertenece a Acme. Su token válido no permite leer una factura de otra empresa, ni una factura de otro usuario de Acme en esta política. Autenticar responde quién eres; autorizar decide qué puedes hacer. Ocultar botones o usar identificadores difíciles de adivinar no impone esa política.

2. El token y su contrato de seguridad

Este JWT firmado tiene cabecera, contenido y firma en base64url. Su contenido es legible: no incluyas contraseñas, pagos ni documentos privados. La firma detecta cambios, pero no cifra.

El perfil exige HS256 y al menos 32 bytes aleatorios de clave del servidor. iss identifica al emisor; aud la API destinataria; sub al usuario; tenant a la organización; iat/exp son segundos Unix enteros. La duración máxima es cinco minutos y typ nf-access+jwt distingue este uso. Son requisitos explícitos de esta aplicación, no de cualquier JWT.

Con HS256, cualquier verificador posee el secreto que también permite emitir tokens. Para varios servicios considera firmas asimétricas y claves públicas/JWKS fiables. Fija algoritmo y origen de claves; una cabecera recibida no puede elegir una URL o archivo arbitrario.

3. Implementar en tu lenguaje

El módulo usa jose. issue() presupone autenticación y organización resueltas por el servidor; verify() comprueba firma y perfil, y canReadInvoice() aplica propiedad y organización. Guarda una clave estable en un gestor de secretos, sin generarla en cada petición. Los tests usan claves desechables.

Un perfil de token, tres lenguajes
import {SignJWT,jwtVerify} from 'jose';
const issuer='https://auth.example.test', audience='billing-api';
function checkKey(key){if(!(key instanceof Uint8Array)||key.length<32)throw new Error('Use at least 32 random bytes');}
export async function issue(subject,tenant,key){
 checkKey(key);
 if(!subject||!tenant)throw new Error('Missing identity');
 return new SignJWT({tenant}).setProtectedHeader({alg:'HS256',typ:'nf-access+jwt'})
  .setSubject(subject).setIssuer(issuer).setAudience(audience)
  .setIssuedAt().setExpirationTime('5m').sign(key);
}
export async function verify(token,key){
 checkKey(key);
 const {payload}=await jwtVerify(token,key,{
  algorithms:['HS256'],typ:'nf-access+jwt',issuer,audience,
  requiredClaims:['exp','iat','sub','tenant'],maxTokenAge:'5m',clockTolerance:0,
 });
 const now=Math.floor(Date.now()/1000);
 if(typeof payload.sub!=='string'||!payload.sub||typeof payload.tenant!=='string'||!payload.tenant||
  !Number.isInteger(payload.exp)||!Number.isInteger(payload.iat)||payload.iat>now||
  payload.exp<=payload.iat||payload.exp-payload.iat>300)throw new Error('Invalid access profile');
 return payload;
}
export function canReadInvoice(actor,invoice){
 return !!actor?.sub&&!!actor?.tenant&&actor.tenant===invoice?.tenant&&actor.sub===invoice?.owner;
}

4. Python con PyJWT

PyJWT valida firma y declaraciones estándar según la configuración. Exigir un campo no verifica su significado: también comprobamos identidades no vacías, tiempos enteros, tipo y duración. Un contenido decodificado sin verificar no es una identidad autenticada.

5. PHP y las declaraciones de la aplicación

PHP-JWT valida firma y fechas; la aplicación comprueba emisor, destinatario y perfil. Aquí aud debe ser la cadena billing-api. Otros proveedores pueden usar listas: adapta el contrato conscientemente sin eliminar controles para aceptar otro formato.

6. Protegerlo en una aplicación real

Un bearer robado se puede reutilizar hasta su caducidad o revocación. Usa HTTPS, oculta Authorization en registros y evita tokens en URL. Una cookie HttpOnly y Secure impide su lectura por JavaScript; ajusta SameSite y protege de CSRF las peticiones que modifican datos. No corrige XSS. localStorage queda expuesto a scripts inyectados; en una app nativa usa almacenamiento protegido del sistema.

Caducar pronto no implementa cerrar sesión. La invalidación inmediata requiere comprobación de sesión/versión o revocación. Los refresh tokens necesitan almacenamiento, rotación, detección de reutilización y revocación propios. Cambia claves con solapamiento controlado. Los permisos pueden cambiar antes de exp: consulta la autorización actual del servidor para acciones sensibles. Estos mecanismos quedan fuera del laboratorio.

7. Ejecutar y entender el resultado

Elige un lenguaje o compara los tres. El ZIP incluye módulos, tests y archivos de bloqueo JavaScript/PHP. La instalación requiere el entorno correspondiente y acceso a registros de paquetes; no usa claves API ni credenciales reales.

Los tests aceptan el token válido y rechazan firma incorrecta, caducidad, campos ausentes, emisor/destinatario/tipo incorrectos, emisión futura, duración excesiva y clave corta. Comprueban propiedad en la misma empresa. JavaScript y PHP imprimen 16 aserciones superadas; Python ejecuta un método con casos equivalentes. No son tests HTTP.

bash
# Choose ONE language; extract the ZIP into a new folder first.
# JavaScript / Node.js 22+
npm ci
npm test

# Python 3.9+ (macOS/Linux; Windows: .venv\Scripts\activate)
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements.txt
python -m unittest test_python.py
python jwt_example.py

# PHP 8.1+ and Composer
composer install --no-plugins --no-scripts
php test_php.php
php jwt_example.php

8. Implementarlo con IA y exigir pruebas

El prompt pide inspeccionar el framework antes de cambiar autenticación. Adapta emisor y destinatario a tu despliegue sin compartir secretos. Exige un cambio pequeño, comando de test y resultado real.

English AI prompt
Act as a senior application engineer. First inspect the existing authentication
framework and explain whether an opaque server session or a JWT is appropriate.
Do not replace a working authentication system just to introduce JWTs.
If JWT access tokens are justified, implement the provided local access profile:
pinned HS256, at least 32 random key bytes, issuer https://auth.example.test,
audience billing-api, typ nf-access+jwt, non-empty sub and tenant, required
integer iat and exp, maximum lifetime 300 seconds and no future issued-at.
Use jose, PyJWT or PHP-JWT according to the actual project language.
Issue tokens only after trusted authentication. Enforce object ownership and
tenant membership in server authorization on every relevant request.
Never derive a signing key, accepted algorithm or tenant from request JSON.
Propose browser storage, CSRF protection, logout/revocation and key rotation
for this application before coding. Do not log tokens or secrets.
Add negative tests for bad signatures, expiration, missing claims, wrong issuer,
audience and token type, another tenant and a non-owner. Report real test output.
Stop before deployment.

9. Ejemplo de una respuesta útil

El ejemplo ilustra el formato esperado, no una auditoría de tu aplicación. Decir que el JWT ya es seguro no demuestra nada. Una respuesta útil relaciona requisito, código, test negativo y duda de integración pendiente. Después usa el prompt de revisión independiente.

Example and interpretation
Requirement: reject a token intended for another API.
Evidence: verify() supplies audience="billing-api".
Negative test: a correctly signed token with aud="other-api" is rejected.
Remaining gap: verify the real HTTP middleware invokes verify() on every route.
This example is an expected review format, not a certification.

10. Lo construido y el siguiente paso

Tienes un perfil reproducible en tres lenguajes y separas identidad de permisos. Conéctalo a tu login y middleware HTTP; prueba errores, permisos actuales, cookies/CSRF, renovación, cierre de sesión y rotación. Empieza por un endpoint que admita al propietario y rechace accesos entre empresas.

English AI prompt
Review this local JWT implementation independently. Produce a table with:
requirement, exact code location, positive test, negative test and remaining gap.
Explain the difference between decoding, signature verification and authorization.
Check key entropy, algorithm pinning, required claims, issuer/audience/type,
short lifetime, server-derived identity, browser storage and token revocation.
Report confirmed defects separately from unverified integration assumptions.
Use only synthetic tokens. Never ask me to paste production credentials.

Referencias oficiales y lecturas

Llévalo a tu proyecto

Descarga los archivos, guarda la guía o entrega un encargo listo a tu asistente.

Preparar con IA

Copia este prompt inglés en tu asistente. Incluye el artículo, los archivos disponibles y los pasos de preparación.

Ver el prompt de preparación
AI setup prompt · English
Read this tutorial as reference material:
https://nethanelfitoussi.com/article/jwt-tokens-security-ai?lang=en

Goal: apply the documented workflow to my development project.
Read the existing project instructions, inspect the relevant files and explain the smallest useful setup.

Available starter files:
https://nethanelfitoussi.com/api/media/aba77d81-4cfd-4614-bca5-53015d625dff.zip
Download and inspect these files in a temporary folder before using them. Do not overwrite existing project instructions.

If I have not supplied a project folder, ask which development project to use. Do not invent a repository URL.

Additional project setup instructions:
Extract the supplied ZIP into a NEW folder. Read README.md before installing or running code.

Act as a senior application engineer. First inspect the existing authentication
framework and explain whether an opaque server session or a JWT is appropriate.
Do not replace a working authentication system just to introduce JWTs.
If JWT access tokens are justified, implement the provided local access profile:
pinned HS256, at least 32 random key bytes, issuer https://auth.example.test,
audience billing-api, typ nf-access+jwt, non-empty sub and tenant, required
integer iat and exp, maximum lifetime 300 seconds and no future issued-at.
Use jose, PyJWT or PHP-JWT according to the actual project language.
Issue tokens only after trusted authentication. Enforce object ownership and
tenant membership in server authorization on every relevant request.
Never derive a signing key, accepted algorithm or tenant from request JSON.
Propose browser storage, CSRF protection, logout/revocation and key rotation
for this application before coding. Do not log tokens or secrets.
Add negative tests for bad signatures, expiration, missing claims, wrong issuer,
audience and token type, another tenant and a non-owner. Report real test output.
Stop before deployment.

Review this local JWT implementation independently. Produce a table with:
requirement, exact code location, positive test, negative test and remaining gap.
Explain the difference between decoding, signature verification and authorization.
Check key entropy, algorithm pinning, required claims, issuer/audience/type,
short lifetime, server-derived identity, browser storage and token revocation.
Report confirmed defects separately from unverified integration assumptions.
Use only synthetic tokens. Never ask me to paste production credentials.

Adapt example paths, commands and acceptance criteria to this repository rather than assuming they match.

Give me a short plan, then make the agreed local changes and run the relevant checks. Report actual results and anything not verified. Stop before credentials, paid services, production changes, push, merge or deployment.
Consultar la fuente originalIETF · JWT security practices
JWTAuthenticationCybersecurityAI