19-payload
Excelente pregunta. La clave secreta (o secret key) NO va dentro del payload ni del header del JWT. Es un error común pensar que se incluye ahí, pero hacerlo sería una grave vulnerabilidad de seguridad.
La clave secreta es un dato externo y privado que solo deben conocer:
El servidor que genera (firma) el token (por ejemplo, tu backend/API).
El servidor que verifica (valida) el token (de nuevo, tu backend/API).
¿Dónde y cómo se usa entonces la Clave Secreta?
La clave secreta se utiliza exclusivamente para crear y verificar la Firma (la tercera parte del JWT).
El proceso es el siguiente:
1. Para CREAR (firmar) el JWT:
Se crean el
headery elpayloaden formato JSON.Se codifican ambos en Base64Url para formar
encodedHeaderyencodedPayload.Se concatenan con un punto:
encodedHeader + "." + encodedPayload.Se toma esta cadena concatenada y se aplica el algoritmo de firma (el especificado en
header.alg, como HS256) junto con la clave secreta para generar la firma.
Fórmula de la firma (ejemplo para HS256):
signature = HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
**secretKey** // <- ¡Aquí se usa la clave!
);Finalmente, se codifica esta firma en Base64Url y se junta todo:
encodedHeader + "." + encodedPayload + "." + encodedSignature
2. Para VERIFICAR el JWT:
Cuando el cliente (navegador, app móvil) te envía el JWT en una solicitud, tu servidor debe verificar que es auténtico y no ha sido alterado.
El servidor separa el token en sus tres partes:
header,payloadysignature.Toma las primeras dos partes (
headerypayloadcodificados) y, usando la misma clave secreta que usó para firmar, vuelve a calcular la firma de la misma manera que en el paso 1.Compara la firma que acaba de calcular con la firma que vino en el token.
Si coinciden: Significa que el token es auténtico y su contenido (
headerypayload) no ha sido modificado. El servidor puede confiar en la información del payload (como eliddel usuario).Si NO coinciden: Significa que el token fue alterado o no fue firmado con la clave correcta. El servidor debe rechazar la solicitud inmediatamente.
Analogía: Un documento firmado
Piensa en el JWT como un documento legal:
El Header es la portada que dice "Contrato".
El Payload es el contenido del contrato (cláusulas, nombres, fechas).
La Firma es tu firma manuscrita al final del documento.
La Clave Secreta es el bolígrafo con tinta única e imposible de copiar que usas para firmar.
Tú no escribes el bolígrafo dentro del contrato. El bolígrafo es tu herramienta privada para demostrar que fuiste tú quien autenticó el contenido del documento. Cualquiera puede leer el contrato (header y payload), pero solo quien tenga el bolígrafo original puede verificar si la firma es válida.
Resumen crucial:
✅ CORRECTO: La clave secreta es un dato externo, guardado de forma segura en tu servidor (en variables de entorno o un gestor de secretos). Se usa para generar y verificar la firma.
❌ INCORRECTO (Y MUY PELIGROSO): Incluir la clave secreta dentro del
payloadoheader. Si haces esto, cualquier persona que decodee el JWT (algo muy fácil) podrá robar tu clave y firmar tokens falsos, comprometiendo toda tu aplicación.
En tu ejemplo, los únicos datos que deben ir en el payload son los del usuario (id, nombre) y claims estándar como iat o exp. La clave nunca debe ser uno de ellos.
*******************************
Así es, la clave secreta es una cadena que tú generas o proporcionas. Es un secreto que solo tu servidor (o servidores) debe conocer.
El proceso, tal como lo describes, es:
Tú defines la clave secreta: Es una cadena de texto larga, compleja y aleatoria. Por ejemplo, podría ser algo como:
fGh3$kL9!pQrS@vXyZ*2w5z8C&E)H+McQeThWmZq4t7w9z$C&F)J@NcRfUjXn2r5u(nunca uses ejemplos, genera una propia). Esta clave se guarda de forma segura en el entorno de tu servidor.Construyes el Header y el Payload: Con la información que quieres transmitir (id, nombre, etc.).
Aplicas el algoritmo de firma: Usas una función (generalmente proporcionada por una librería de JWT) que hace exactamente lo que dices:
Toma el
headercodificado en Base64Url.Toma el
payloadcodificado en Base64Url.Los concatena con un punto.
Aplica el algoritmo (ej: HS256) junto con tu clave secreta a esa cadena concatenada para generar la firma.
Ejemplo Práctico con Código (Pseudocódigo)
Imagina que tienes estos datos:
// 1. Tu Clave Secreta (guardada en el servidor)
const secretKey = 'mi-clave-super-secreta-y-compleja-2024';
// 2. Header y Payload
const header = {
"alg": "HS256",
"typ": "JWT"
};
const payload = {
"id": 5421,
"nombre": "Ana García",
"clave_de_usuario": "abc123" // ¡Ojo! Esto es la clave DEL USUARIO, no la secreta para firmar.
};
// 3. Una librería de JWT haría esto por ti:
const encodedHeader = base64UrlEncode(JSON.stringify(header));
const encodedPayload = base64UrlEncode(JSON.stringify(payload));
const dataToSign = encodedHeader + '.' + encodedPayload;
// 4. Aquí es donde usas tu "secretKey" para crear la firma.
// La función HMACSHA256 es el algoritmo HS256.
const signature = HMACSHA256(dataToSign, secretKey);
const encodedSignature = base64UrlEncode(signature);
// 5. Juntas todo para formar el JWT
const jwtToken = encodedHeader + '.' + encodedPayload + '.' + encodedSignature;
// Resultado: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTQyMSwibm9tYnJlIjoiQW5hIEdhcmPDrWEiLCJjbGF2ZV9kZV91c3VhcmlvIjoiYWJjMTIzIn0.XL4eSmY4UZQQP2fCq7g2a7xRkXeoRkZz7J2lT6p1qQ0Punto importante: En el ejemplo del payload puse "clave_de_usuario": "abc123". Esto es la contraseña o PIN del usuario en tu sistema, no es la clave secreta para firmar el JWT. Es mala práctica incluir información sensible como contraseñas en el payload, ya que aunque el JWT está firmado, su contenido (payload) es fácilmente decodificable y visible por cualquiera (no está encriptado, solo codificado en Base64).
En resumen: Sí, tu entendimiento es correcto. La clave secreta es externa y se usa junto con el algoritmo para crear la firma, que es la garantía de integridad y autenticidad del token
*********************
No, exactamente. Es un error común y potencialmente peligroso pensar así. Vamos a aclararlo.
El payload NO se "toma" directamente de la base de datos para copiar todos los campos del usuario. Tú construyes deliberadamente el payload con la información específica que tu aplicación necesita para validar requests futuras, sin tener que consultar la base de datos cada vez.
La Relación Correcta entre la Base de Datos y el Payload del JWT
La Base de Datos es la Fuente de Verdad: Contiene toda la información del usuario (ID, nombre, email, hash de la contraseña, roles, permisos, etc.).
El Payload del JWT es un "Resumen de Claims": Cuando un usuario inicia sesión correctamente (es decir, verficas su usuario y clave contra la base de datos y son válidos), entonces tú:
Generas un nuevo JWT.
Decides qué información del usuario es relevante para incluir en el payload de ese token. Esta información se usará para procesar las solicitudes posteriores del cliente.
¿Qué información suele ir en el Payload?
La información que permite identificar al usuario y tomar decisiones de autorización inmediatas, sin necesidad de hacer una consulta a la base de datos en cada request.
Información Típica y Recomendada:
sub(subject): El ID único del usuario en tu base de datos. Este es el claim más importante. Es la llave que te permitiría, si fuera necesario, buscar más información del usuario en la BD.name,email: Datos básicos para personalizar la interfaz.roleoscope: Los permisos o el rol del usuario (e.g.,"admin","user","read:posts"). Esto te permite hacer autorización básica (¿puede este usuario acceder a esta ruta?).iat(issued at): Fecha de emisión del token.exp(expiration time): Fecha de expiración. Crucial para la seguridad.
¡LO MÁS IMPORTANTE: Qué NO debe ir en el Payload!
❌ NUNCA pongas la contraseña del usuario (ni en texto plano ni hasheada).
❌ Evita poner información extremadamente sensible como números de tarjetas de crédito, direcciones exactas, etc. Recuerda que el payload solo está codificado en Base64, no está encriptado. Cualquiera puede decodificarlo y leerlo fácilmente.
❌ No incluyas datos innecesarios que hagan el token muy grande (como una lista de todos los pedidos del usuario). El token se envía en cada request y un tamaño excesivo afecta el performance.
Ejemplo del Flujo Correcto
Imagina que tu tabla de usuarios en la BD tiene estos campos: id, nombre, email, password_hash, rol, fecha_creacion.
Login: El usuario envía
{ "usuario": "ana", "clave": "miClave123" }.Verificación en BD: Tu backend busca el usuario "ana", encuentra su
password_hashy verifica que "miClave123" coincida.Construcción del Payload: Si la clave es correcta, construyes el payload con la información necesaria del usuario que encontraste en la BD, pero no toda.
// Este es el payload que CONSTRUYES, no que copias tal cual de la BD.
{
"sub": 5421, // El 'id' de la BD. Es el dato más crucial.
"name": "Ana García", // El 'nombre' de la BD.
"email": "ana@ejemplo.com", // El 'email' de la BD.
"rol": "admin", // El 'rol' de la BD.
"iat": 1516239022,
"exp": 1516242622
}Generación del JWT: Firmas este payload con tu clave secreta y se lo envías al cliente.
Requests Futuras: El cliente envía el JWT en cada request. Tú verificas la firma y, si es válida, usas la información del payload (como
sub: 5421yrol: "admin") para saber quién es el usuario y si tiene permisos para realizar la acción, todo sin consultar la base de datos de nuevo.
Conclusión
El payload no es un volcado de la base de datos. Es un conjunto de claims cuidadosamente seleccionados que representan una "sesión" o "identidad" verificada para ese usuario, que tu servidor puede confiar porque la firma es válida.
En resumen: Usas la base de datos para verificar el login, pero luego construyes un token con la información mínima necesaria para evitar seguir consultando la base de datos en cada paso.-
******************************
Estos datos son claims estándar del JWT que representan marcas de tiempo. Son absolutamente esenciales para la seguridad y funcionalidad de los tokens.
iat (Issued At - Emitido En)
Qué es: La fecha y hora en la que el token fue creado o emitido.
El valor: Es un número que representa el Timestamp Unix, también conocido como época Unix.
Cómo se calcula: Es el número de segundos que han transcurrido desde el 1 de enero de 1970 a las 00:00:00 UTC (excluyendo segundos intercalares).
Propósito:
Saber la edad del token. Por ejemplo, puedes tener una política de seguridad que no acepte tokens que tengan más de 2 días, aunque no hayan expirado.
Es una información de auditoría útil.
exp (Expiration Time - Tiempo de Expiración)
Qué es: La fecha y hora exacta en la que el token dejará de ser válido. Después de este momento, cualquier intento de usar el token debe ser rechazado por el servidor.
El valor: También es un Timestamp Unix.
Cálculo típico: Se establece sumando un período de tiempo válido al momento de la creación (
iat).En tu ejemplo:
exp(1516242622) -iat(1516239022) = 3600 segundos.¡Esto significa que este token es válido sólo por 1 hora (3600 segundos)!
Propósito:
Seguridad. Es la característica más importante para limitar la ventana de tiempo en la que un token robado o comprometido puede ser usado por un atacante. Sin una expiración, los tokens serían credenciales permanentes.
¿Por qué son tan importantes?
Imagina que un hacker roba el token de un usuario. Si el token no tuviera exp, sería válido para siempre, dando al atacante acceso permanente a la cuenta.
Con el exp, incluso si el token es robado, el acceso del atacante tendrá una duración limitada (por ejemplo, 1 hora, 8 horas, etc.). Esto mitiga enormemente el daño.
Ejemplo Práctico en Código
Cuando generas un token, lo haces así (ejemplo en JavaScript):
const jwt = require('jsonwebtoken');
const secretKey = 'mi-clave-secreta';
// 1. Calculamos los timestamps
const iat = Math.floor(Date.now() / 1000); // Fecha/hora actual en segundos
const exp = iat + (60 * 60); // Expira en 1 hora (iahora + 3600 segundos)
// 2. Construimos el payload INCLUDIENDO iat y exp
const payload = {
sub: 5421,
name: "Ana García",
iat: iat, // 👈 Se añade el momento de creación
exp: exp // 👈 Se añade el momento de expiración
};
// 3. Generamos el token
const token = jwt.sign(payload, secretKey);
console.log(token);¿Cómo los usa el Servidor?
Cuando recibes un token, las librerías JWT verifican automáticamente la firma y la expiración. Si Date.now() / 1000 (el tiempo actual) es mayor que el valor de exp, la verificación fallará y devolverá un error.
En resumen:
iat: El "sello de tiempo" que dice cuándo nació el token.exp: La "fecha de caducidad" que dice cuándo morirá el token. Es tu principal mecanismo de defensa contra tokens robados
Excelente pregunta. La respuesta es:
¡Tú los proporcionas! O, más específicamente, tu código en el servidor es el que los genera y añade al payload justo antes de firmar el token.
No son datos que vengan de la base de datos del usuario ni los proporciona el cliente. Son metadatos sobre el token mismo que tu servidor calcula sobre la marcha en el momento exacto en que el token está siendo creado.
El Proceso Paso a Paso:
El usuario se loguea: Envía su nombre de usuario y contraseña.
Tú verificas las credenciales: Consultas la base de datos para comprobar que son correctas.
Tú decides la validez del token: En tu código del servidor, tienes una configuración que dice cuánto tiempo debe ser válido un token (ej: "1 hora", "7 días"). Esto suele estar en una variable de entorno como
JWT_EXPIRES_IN.Tú calculas los timestamps:
Obtienes la fecha/hora actual del sistema de tu servidor.
Conviertes esa fecha/hora a un timestamp Unix (segundos desde 1970). Esto es el
iat.Le sumas el tiempo de validez (en segundos) al
iatpara obtener elexp.
Construyes el payload: Creas el objeto que incluye tanto los datos del usuario (id, nombre, etc.) como los timestamps
iatyexpque acabas de calcular.Firmas el token: Usas una librería JWT para firmar este payload completo con tu clave secreta y se lo envías al cliente.
Ejemplo Práctico con Código (Node.js)
// Este es tu código en el backend (API)
const jwt = require('jsonwebtoken');
// 1. Estas variables las defines TÚ en tu servidor.
const secretKey = process.env.JWT_SECRET; // Tu clave secreta
const expiresIn = '1h'; // TÚ decides: "1h", "7d", "15m", etc.
// 2. Función que se ejecuta cuando el login es correcto
function generarToken(userDataFromDB) {
// 3. TÚ construyes el payload manualmente, combinando:
const payload = {
// Datos del usuario de la BD
sub: userDataFromDB.id,
name: userDataFromDB.name,
role: userDataFromDB.role,
// Metadatos del token que TÚ calculas ahora:
iat: Math.floor(Date.now() / 1000), // <-- Fecha actual en segundos
// 'exp' no hace falta ponerlo manualmente si usas la opción 'expiresIn' en .sign()
};
// 4. La librería JWT se encarga de añadir 'exp' automáticamente basado en el 'iat' y el 'expiresIn'
const token = jwt.sign(
payload,
secretKey,
{ expiresIn: expiresIn } // <-- TÚ proves esta opción
);
return token;
}
// Uso: Cuando el login es exitoso, llamas a esta función:
// const token = generarToken({ id: 5421, name: 'Ana García', role: 'admin' });Nota: En este ejemplo, la librería jsonwebtoken es lo suficientemente inteligente como para tomar el iat actual y calcular el exp por sí misma si usas la opción expiresIn. Pero el concepto es el mismo: eres tú quien, a través de tu código y configuración, proporciona estos valores.
Resumen:
iatlo calcula tu servidor con la fecha/hora actual (Date.now()).explo calcula tu servidor sumando el tiempo de validez que tú configuraste (expiresIn) aliat.Ambos son añadidos al payload por tu código antes de firmar el token.
El cliente (navegador, app móvil) nunca se preocupa por estas fechas. Su único trabajo es almacenar el token y enviarlo en cada petición. Es responsabilidad del servidor verificarlas cada vez que recibe un token para asegurarse de que aún es válido.
*******************************
Te lo explico paso a paso de cómo se obtuvieron o calcularon esos valores exactos (1516239022 y 1516242622).
1. iat (Issued At - Emitido a las):
El valor 1516239022 es un timestamp Unix. Representa un momento específico en la historia.
¿Qué es un timestamp Unix? Es el número de segundos que han transcurrido desde la Época Unix, que es la medianoche (00:00:00 UTC) del 1 de enero de 1970.
¿Cómo se obtuvo? En el momento exacto en que el servidor generó el token, ejecutó código similar a este para obtener la fecha/hora actual y convertirla a segundos:
// Código en el servidor en el momento de crear el token:
const fechaActual = new Date(); // Crea un objeto con la fecha y hora exactas del servidor
const iat = Math.floor(fechaActual.getTime() / 1000); // Convierte milisegundos a segundos
console.log(iat); // Esto imprimiría 1516239022 (o el valor que corresponda a ESE momento)Traducción: El token fue generado exactamente 1,516,239,022 segundos después de las 00:00:00 del 01/01/1970.
Si convertimos ese número a una fecha legible para humanos (usando una herramienta como epochconverter.com), descubrimos que:
1516239022 corresponde a:
Monday, January 18, 2018 11:30:22 AM UTC
2. exp (Expiration Time - Tiempo de Expiración):
El valor 1516242622 es también un timestamp Unix que representa el momento en que el token dejó de ser válido.
¿Cómo se obtuvo? El servidor sumó una cantidad predefinida de segundos al valor
iat. Es una operación matemática simple.
// Código en el servidor:
const tiempoDeVidaDelToken = 60 * 60; // 3600 segundos = 1 hora
const exp = iat + tiempoDeVidaDelToken; // 1516239022 + 3600
console.log(exp); // Esto da como resultado 15162426221516242622 - 1516239022 = 3600. Esto confirma que el token fue configurado para expirar exactamente una hora (3600 segundos) después de haber sido emitido.
La fecha legible para este exp sería:
Monday, January 18, 2018 12:30:22 PM UTC
(Una hora después del iat).
Resumen del Proceso en el Servidor:
Paso 1 (Obtener el momento actual): El servidor usa la función del sistema
Date.now()para obtener el instante preciso en que el usuario hizo login correctamente.Paso 2 (Calcular
iat): Convierte ese instante de milisegundos a segundos.Paso 3 (Definir la validez): Tú, como desarrollador, has decidido que los tokens duren 1 hora. Esto está hardcodeado o en una configuración.
Paso 4 (Calcular
exp): El servidor suma3600(segundos) al valor deiat.Paso 5 (Armar el Payload): Se crea el objeto JSON con el
id(sub),name,roldel usuario y se le agregan los valores calculadosiatyexp.Paso 6 (Firmar): Este payload se firma con la clave secreta para crear el JWT final.
En conclusión: Estos valores no son aleatorios ni vienen de la base de datos. Son el resultado de una operación matemática simple que tu servidor realiza en tiempo real usando el reloj del sistema y la configuración de duración que tú le diste.
******************
¡Exactamente! Tú configuras tu propio exp decidiendo cuánto tiempo quieres que el token sea válido. Es una de las decisiones de seguridad más importantes al trabajar con JWTs.
Hay dos formas principales de hacerlo, dependiendo de la librería JWT que uses. Ambas son correctas, pero la primera es más común y sencilla.
Opción 1 (Recomendada y Más Común): Dejar que la librería lo calcule automáticamente
La mayoría de las librerías JWT te permiten especificar un tiempo de vida (expiresIn) al firmar el token. La librería se encarga de calcular el iat (la hora actual) y sumarle el tiempo que le indiques para generar el exp automáticamente.
Ejemplos en diferentes lenguajes:
Node.js (con la librería jsonwebtoken)
const jwt = require('jsonwebtoken');
const secretKey = 'tu-clave-super-secreta';
const payload = {
sub: 5421,
name: "Ana García",
role: "admin"
// ¡Nota que NO incluyo 'iat' ni 'exp' manualmente!
};
// CONFIGURAS el 'exp' aquí, en la opción 'expiresIn'
const token = jwt.sign(
payload,
secretKey,
{ expiresIn: '1h' } // 👈 ¡TÚ CONFIGURAS LA EXPIRACIÓN AQUÍ!
);
console.log(token);En este caso, la librería añadirá automáticamente los campos iat y exp al payload antes de firmarlo. Tú solo defines la duración.
Python (con la librería PyJWT)
import jwt
import datetime
secretKey = "tu-clave-super-secreta"
payload = {
"sub": 5421,
"name": "Ana García",
"role": "admin"
# No se añaden iat ni exp manualmente
}
# CONFIGURAS el 'exp' aquí, estableciendo un tiempo de vida
token = jwt.encode(
{
**payload,
"exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1) # 👈 1 hora
},
secretKey,
algorithm="HS256"
)
print(token)Opción 2: Calcularlo manualmente y añadirlo al payload
Si necesitas un control más granular o tu librería no soporta la opción expiresIn, puedes calcular el exp manualmente.
Ejemplo en Node.js:
const jwt = require('jsonwebtoken');
const secretKey = 'tu-clave-super-secreta';
// 1. Tú calculas el momento de creación (iat)
const iat = Math.floor(Date.now() / 1000); // Timestamp actual en segundos
// 2. TÚ DECIDES y calculas la expiración (exp)
// ¿Cuánto quieres que dure? Por ejemplo, 1 hora = 3600 segundos
const tiempoDeVidaEnSegundos = 60 * 60; // 3600 segundos
const exp = iat + tiempoDeVidaEnSegundos; // 👈 ¡Tú configuras esto!
const payload = {
sub: 5421,
name: "Ana García",
role: "admin",
iat: iat, // Añadido manualmente
exp: exp // Añadido manualmente 👈
};
// 3. Firmas el token (sin la opción expiresIn)
const token = jwt.sign(payload, secretKey);
console.log(token);¿Cómo decides el valor de expiresIn o tiempoDeVidaEnSegundos?
Esta es una decisión de seguridad y usabilidad que tomas como desarrollador. No hay una respuesta única, pero aquí hay algunas pautas:
Tokens de acceso cortos (más seguros): 15 minutos - 1 hora. Ideales para aplicaciones muy sensibles (banca). Limitan mucho el daño si un token es robado, pero obligan al usuario a renovar el token con frecuencia (usando un Refresh Token).
Tokens de acceso estándar: 2 - 8 horas. Un buen equilibrio para la mayoría de las aplicaciones web. El usuario puede navegar durante una sesión típica sin tener que volver a loguearse.
Tokens de acceso largos (menos seguros): 7 días - 30 días. Usual en aplicaciones donde la comodidad del usuario es prioritaria (ej., la app móvil de tu red social donde no quieres que te pida la contraseña cada semana). Aumenta el riesgo si el token es robado.
La configuración típica suele estar en una variable de entorno:
// En tu archivo .env o configuración
JWT_EXPIRES_IN=2h
// En tu código
const token = jwt.sign(payload, secretKey, { expiresIn: process.env.JWT_EXPIRES_IN });Conclusión:
Tú configuras el exp decidiendo cuánto tiempo debe vivir el token (expiresIn) y dejando que la librería haga el cálculo, o calculándolo manualmente (iat + duración) y añadiéndolo al payload antes de firmar.
La Opción 1 es casi siempre la mejor porque es más simple y menos propensa a errores
Comentarios
Publicar un comentario