Qué es un token JWT y cómo se utiliza

JavascriptPHP

Los tokens JWT son un es estándar que se utiliza para crear tokens de acceso a las aplicaciones, permitiendo la autenticación de usuarios en aplicaciones web. En concreto, se sigue el estándar RFC 7519.

Qué es un token JWT

Un token JWT es un token que da acceso al usuario a una aplicación certificando su identidad. Este token se devuelve al cliente, que suele ser el navegador del usuario, enviando el token de vuelta al servidor con cada una de las sucesivas peticiones. De este modo, el servidor sabe si la petición procede o no de un determinado usuario.

Este tipo de diseño es muy habitual cuando tenemos una aplicación frontend que accede al servidor a través de una API REST o GraphQL. El usuario se autenticará enviando sus datos de acceso al servidor y éste creará y devolverá un token JWT si los datos de acceso son correctos. Es importante no confundir autenticación con autorización, ya que son dos procesos diferentes. El token se almacenará en el navegador del usuario, para lo cual se suele usar una cookie.

Cuando uses un token JWT tendrás que usar una conexión segura HTTPS. Esto es debido a que los tokens no están encriptados, ya que sencillamente están firmados criptográficamente por el servidor. En teoría, mediante una conexión segura, ningún usuario podrá interceptar o modificar el token en su transcurso del origen a su destino y viceversa.

Cómo generar un token JWT

El método utilizado para generar un token JWT varía en función del lenguaje de programación y de las funciones o librerías utilizadas para tal fin. A continuación vamos a ver cómo generar un token JWT tanto con JavaScript como con PHP.

Token JWT con JavaScript

Vamos a ver cómo generar un token JWT con Node.js. Lo único que necesitarás es tener Node.js instalado en tu sistema e inicializar cualquier proyecto.

Luego debes usar el siguiente código, en donde debes crear un objeto JSON en el que se establezca el algoritmo HMAC SHA256 como algoritmo de cifrado, aunque podrías usar cualquier otro que esté soportado. Luego generamos un Buffer a partir del objeto y lo codificamos como una cadena base64:

const cabecera = { "alg": "HS256", "typ": "JWT" };
const cabeceraCodificada = Buffer.from(JSON.stringify(cabecera)).toString('base64');

Seguidamente debes agregar los datos del usuario, sean cuales sean los elementos que identifiquen al usuario. Estos datos podrían ser el nombre de usuario del sistema o su identificador. Puedes agregar los datos que consideres necesarios. La única excepción a los elementos del objeto que contiene los datos son las claves iss y exp, que son palabras clave que no podrás agregar y que sirven para establecer el emisor del toquen y su fecha de expiración.

También tendremos que convertir el objeto en un Buffer y codificarlo como una cadena base64. A continuación puedes ver un ejemplo:

const datos = { id: 'id_usuario' };
const datosCodificados = Buffer.from(JSON.stringify(datos)).toString('base64');

Seguidamente, vamos a importar el módulo crypto de Node.js y a establecer una clave secreta con la que firmar el token. Puedes usar cualquier otra librería que cumpla este cometido. Luego generaremos la firma a partir de la cabecera cabeceraCodificada y los datos del usuario datosCodificados. Usaremos la firma y la clave secreta para generar una representación base64 de la firma encriptada.

const crypto = require('crypto');
const claveSecreta = 'clave_secreta';

const firma = crypto.createHmac('sha256', claveSecreta).update(cabeceraCodificada + '.' + datosCodificados).digest('base64');

Con esto evitamos que el contenido pueda ser modificado, ya que esto invalidaría la firma.

Ya solamente nos falta concatenar la cabecera codificada, los datos codificados y la firma para generar el token JWT. Para ello usamos una plantilla literal. Los diferentes elementos estarán separados por un punto:

const tokenJWT = `${cabeceraCodificada}.${datosCodificados}.${firma}`;

Token JWT con PHP

Vamos a ver cómo crear un token de autenticación JWT con PHP. Para ello podríamos usar un paquete existente o crear el token desde cero. Vamos a ver ambos casos.

Para crear el token manualmente, primero tenemos crear el objeto JSON que contendrá la cabecera del token, estableciendo el algoritmo HMAC SHA256 como el algoritmo de cifrado, aunque podrías usar cualquier otro que esté soportado. El uso de los nombres typ y alg forman parta el estándar. Luego codificaremos el objeto como una cadena base64:

$cabecera = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
$cabeceraCodificada = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($cabecera));

Luego tendremos que agregar los datos de identificación del usuario en un objeto JSON, pudiendo agregar cualquier clave salvo las palabras reservadas iss y exp, usadas para establecer el emisor del token y la fecha de expiración del mismo respectivamente. También tendremos que generar una cadena en formato base64:

$datos = json_encode(['id' => 'id_usuario']);
$datosCodificados = Buffer.from(JSON.stringify(datos)).toString('base64');

A continuación debemos crear la firma, encriptando la cabecera, los datos y la clave secreta con el algoritmo sha256, para lo cual usaremos la función hash_hmac de PHP. Además, también debemos codificar la firma como una cadena base64:

$claveSecreta = 'clave_secreta';
$firma = hash_hmac('sha256', $cabeceraCodificada. '.' . $datosCodificados, $claveSecreta, true);
$firmaCodificada = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($firma));

Finalmente, crearemos el token JWT uniendo la cabecera codificada, los datos codificados y la firma encriptada y codificada:

$tokenJWT = $cabeceraCodificada . '.' . $datosCodificados . '.' . $firmaCodificada;

Con esto ya habríamos creado el token JWT, aunque existen otros métodos más rápidos mediante los cuales también podremos generar el token.

Por ejemplo, podemos usar uno de los muchos paquetes que facilitan la creación de tokens JWT En concreto, podemos usar la librería ReallySimpleJWT, que puedes instalar mediante composer:

composer require rbdwllr/reallysimplejwt

Para crear un token JWT del modo más sencillo, basta con que usemos el método create de la clase ReallySimpleJWT\Token , que usaremos para crear el token. Este método recibe como parámetros el identificador del usuario, que puede ser su email,  su nombre de usuario o cualquier otro dato que lo identifique. Como segundo parámetro acepta una clave secreta que tendremos que configurar y, como tercer y cuarto parámetro acepta la fecha de expiración del token y el emisor del mismo respectivamente, siendo estos dos últimos parámetros opcionales:

use ReallySimpleJWT\Token;

$idUsuario = 'id_usuario';
$claveSecreta = 'clave_secreta';
$expiracion = time() + 3600;
$emisor = 'localhost';

$tokenJWT = Token::create($idUsuario, $claveSecreta, $expiracion, $emisor);

También podríamos agregar datos adicionales personalizados además del identificador del usuario mediante el método customPayload:

use ReallySimpleJWT\Token;

$datos = [
  'uid' => 'id_usuario',
  'iat' => time(),
  'exp' => time() + 3600,
  'iss' => 'localhost'
];

$claveSecreta = 'clave_secreta';

$token = Token::customPayload($datos, $claveSecreta);

Para validar el token cuando sea devuelto por el cliente, podemos usar el método validate:

use ReallySimpleJWT\Token;

$result = Token::validate($token, $claveSecreta);

Autenticación API con un token JWT

Una vez hayas generado un token JWT, podrás almacenarlo en una cookie HttpOnly, que es lo más seguro, pudiendo así evitar ataques XSS. Esto es debido a que JavaScript no podrá acceder a esta cookie, siendo enviada automáticamente al servidor con cada petición. El proceso que se realizará es el siguiente:

  1. Primero el usuario enviará sus datos de acceso al servidor.
  2. El servidor generará el token JWT en base a dichos datos y lo almacenará en una cookie.
  3. En sucesivas peticiones, el cliente enviará el token JWT al servidor, pudiendo así identificarse.

Si quieres saber cómo gestionar cookies con Express, consulta el tutorial en donde explico cómo usar cookies con Express.

Si usas PHP y quieres saber más cosas acerca de los ataques XSS, consulta la siguiente guía, en donde explico cómo evitar ataques XSS con PHP.

Finalmente, decir que en caso de que lo que quieras almacenar sean datos de sesión, se recomienda encarecidamente que uses las sesiones del servidor de toda la vida.

Esto ha sido todo.


Avatar de Edu Lazaro

Edu Lázaro: Ingeniero técnico en informática, actualmente trabajo como desarrollador web y programador de videojuegos.

👋 Hola! Soy Edu, me encanta crear cosas y he redactado esta guía. Si te ha resultado útil, el mayor favor que me podrías hacer es el de compatirla en Twitter 😊

Si quieres conocer mis proyectos, sígueme en Twitter.

2 comentarios en “Qué es un token JWT y cómo se utiliza

  1. Muchas Gracias por tu trabajo es excelente.

    Pones el mismo trocito de código Buffer.from(JSON.stringify(datos)).toString(‘base64’); tanto en el apartado 2.1 Token JWT con JavaScript como en el apartado 2.2 Token JWT con PHP pero en el caso de php no localizo la orden Buffer en el manual de php ¿quizá corresponde a php antiguo? , ¿o podría deberse la repetición a una equivocación y en php se hace de otra manera?

    Una vez mas muchas gracias.

Deja una respuesta

“- Hey, Doc. No tenemos suficiente carretera para ir a 140/h km. - ¿Carretera? A donde vamos, no necesitaremos carreteras.”