Las cookies llevan tiempo uti­li­zá­n­do­se para au­te­n­ti­fi­car a los usuarios de Internet; y funcionan muy bien para ciertas apli­ca­cio­nes. Sin embargo, a veces es necesaria una mayor fle­xi­bi­li­dad. Aquí entra en juego JSON Web Token, un nuevo estándar abierto que están adoptando cada vez más sitios web y apli­ca­cio­nes im­po­r­ta­n­tes. Te ex­pli­ca­mos qué es un JWT, cómo funciona y en qué casos se utiliza.

¿Qué es un JSON Web Token?

Un JSON Web Token es un token de acceso es­ta­n­da­ri­za­do en el RFC 7519 que permite el in­te­r­ca­m­bio seguro de datos entre dos partes. Contiene toda la in­fo­r­ma­ción im­po­r­ta­n­te sobre una entidad, lo que implica que no hace falta consultar una base de datos ni que la sesión tenga que guardarse en el servidor (sesión sin estado).

Por este motivo, los JWT son es­pe­cia­l­me­n­te populares en los procesos de au­te­n­ti­fi­ca­ción. Con este estándar es posible cifrar mensajes cortos, dotarlos de in­fo­r­ma­ción sobre el remitente y demostrar si este cuenta con los derechos de acceso re­que­ri­dos. Los propios usuarios solo entran en contacto con el token de manera indirecta: por ejemplo, al in­tro­du­cir el nombre de usuario y la co­n­tra­se­ña en una interfaz. La co­mu­ni­ca­ción como tal entre las di­fe­re­n­tes apli­ca­cio­nes se lleva a cabo en el lado del cliente y del servidor.

¿Cómo se es­tru­c­tu­ra un JSON Web Token?

Un JWT firmado consta de tres partes, todas ellas co­di­fi­ca­das en Base64 y separadas por un punto:

HEADER.PAYLOAD.SIGNATURE

¿Qué si­g­ni­fi­can estas tres partes?

Header

El header consta ge­ne­ra­l­me­n­te de dos valores y pro­po­r­cio­na in­fo­r­ma­ción im­po­r­ta­n­te sobre el token. Contiene el tipo de token y el algoritmo de la firma y/o cifrado uti­li­za­dos. Este podría ser un ejemplo de header de un JWT:

{ "alg": "HS256", "typ": "JWT" }

Siempre se re­co­mie­n­da in­tro­du­cir JWT como tipo, que hace re­fe­re­n­cia al tipo de medio ap­pli­ca­tion/jwt de la IANA. En el ejemplo anterior, el header indica que HMAC-SHA256, abreviado como HS256, se utiliza para firmar el token. Otros métodos de cifrado típicos son RSA, con SHA-256 (RS256), y ECDSA, con SHA-256 (ES256). No se re­co­mie­n­da pre­s­ci­n­dir del cifrado, aunque sí se puede es­pe­ci­fi­car none si los datos no requieren un nivel de pro­te­c­ción alto. Los posibles valores están es­ta­n­da­ri­za­dos por JSON-Web-En­cr­y­p­tion según el RFC 7516.

En el caso de los JSON Web Tokens complejos firmados o cifrados, también existe el parámetro cty para content type, que se rellena del mismo modo, con el valor JWT. En el resto de casos, este parámetro se omite.

Payload

El campo payload de JSON Web Token contiene la in­fo­r­ma­ción real que se tra­n­s­mi­ti­rá a la apli­ca­ción. Aquí se definen algunos es­tá­n­da­res que de­te­r­mi­nan qué datos se tra­n­s­mi­ten y cómo. La in­fo­r­ma­ción se pro­po­r­cio­na como pares key/value (clave-valor); las claves se denominan claims en JWT. Hay tres tipos di­fe­re­n­tes de claims:

  • Los claims re­gi­s­tra­dos son los que figuran en el IANA JSON Web Token Claim Register y cuyo propósito se establece en un estándar. Algunos ejemplos son el emisor del token (iss, de issuer), el dominio de destino (aud, de audience) y el tiempo de ve­n­ci­mie­n­to (exp, de ex­pi­ra­tion time). Se utilizan nombres de claim cortos para abreviar el token lo máximo posible.
  • Los claims públicos pueden definirse a voluntad, ya que no están sujetos a re­s­tri­c­cio­nes. Para que no se produzcan co­n­fli­c­tos en la semántica de las claves, es necesario registrar los claims pú­bli­ca­me­n­te en el JSON Web Token Claim Register de la IANA o asi­g­nar­les nombres que no puedan coincidir.
  • Los claims privados están de­s­ti­na­dos a los datos que in­te­r­ca­m­bia­mos es­pe­cia­l­me­n­te con nuestras propias apli­ca­cio­nes. Si bien los claims públicos contienen in­fo­r­ma­ción como nombre o correo ele­c­tró­ni­co, los claims privados son más concretos. Por ejemplo, suelen incluir datos como ide­n­ti­fi­ca­ción de usuario o nombre de de­pa­r­ta­me­n­to. Al no­m­brar­los, es im­po­r­ta­n­te ase­gu­rar­se de que no vayan a entrar en conflicto con ningún claim re­gi­s­tra­do o público.

Todos los claims son op­cio­na­les, por lo que no es obli­ga­to­rio utilizar todos los claims re­gi­s­tra­dos. En general, el payload puede contener un número ilimitado de claims, aunque es aco­n­se­ja­ble limitar la in­fo­r­ma­ción del JWT al mínimo. Cuanto más extenso sea el JWT, más recursos ne­ce­si­ta­rá para la co­di­fi­ca­ción y la de­s­co­di­fi­ca­ción.

Un payload podría es­tru­c­tu­rar­se, por lo tanto, de la siguiente manera:

{ "sub": "123", "name": "Alicia", "exp": 30 }

Firma

La firma de un JSON Web Token se crea uti­li­za­n­do la co­di­fi­ca­ción Base64 del header y del payload, así como el método de firma o cifrado es­pe­ci­fi­ca­do. La es­tru­c­tu­ra viene definida por JSON Web Signature (JWS), un estándar es­ta­ble­ci­do en el RFC 7515. Para que la firma sea eficaz, es necesario utilizar una clave secreta que solo conozca la apli­ca­ción original. Por un lado, la firma verifica que el mensaje no se ha mo­di­fi­ca­do por el camino. Por otro, si el token está firmado con una clave privada, también garantiza que el remitente del JWT sea el correcto.

Existen di­fe­re­n­tes métodos de firma, de­pe­n­die­n­do del nivel de co­n­fi­de­n­cia­li­dad de los datos:

  1. Sin pro­te­c­ción: como hemos me­n­cio­na­do, si los datos no requieren un nivel de pro­te­c­ción alto, puede es­pe­ci­fi­car­se el valor none en el header. En este caso, no se genera ninguna firma y el JWT solo constará de header y payload. Sin esta medida de pro­te­c­ción, el payload puede leerse como texto en claro una vez de­s­ci­fra­do el código Base64 y no se comprueba si el mensaje procede del remitente correcto o si fue mo­di­fi­ca­do al tra­n­s­fe­ri­r­se.
  2. Firma (JWS): por lo general, basta con comprobar si los datos provienen del remitente correcto y si han sido mo­di­fi­ca­dos. Para ello, se utiliza el esquema JSON Web Signature (JWS), que garantiza que el mensaje no se haya cambiado por el camino y proceda del remitente correcto. Con este pro­ce­di­mie­n­to, el payload también puede leerse como texto en claro tras el de­s­ci­fra­do de Base64.
  3. Firma (JWS) y cifrado (JWE): además de JWS, es posible emplear JSON Web En­cr­y­p­tion (JWE). JWE cifra el contenido del payload, que luego se firma con JWS. Para descifrar el contenido, se indica una co­n­tra­se­ña común o una clave privada. De este modo, el remitente se verifica, el mensaje es co­n­fi­de­n­cial y se au­te­n­ti­fi­ca, y el payload no puede leerse como texto en claro tras el de­s­ci­fra­do de Base64.

El cifrado crea una secuencia de ca­ra­c­te­res apa­re­n­te­me­n­te aleatoria:

{ 7WK5T79u5mIzjIXXi2oI9Fglmgivv7RAJ7izyj9tUyQ }
Nota

En cada uno de los métodos an­te­rio­res, es necesario utilizar también SSL para proteger los datos.

¿Cómo funciona un JSON Web Token?

El inicio de sesión de usuario eje­m­pli­fi­ca bien la función del JSON Web Token. Antes de utilizar el JWT, hay que es­ta­ble­cer una clave secreta. Una vez que el usuario ha in­tro­du­ci­do co­rre­c­ta­me­n­te sus cre­de­n­cia­les, el JWT se devuelve con la clave y se guarda lo­ca­l­me­n­te. La tra­n­s­mi­sión debe rea­li­zar­se a través de HTTPS para que los datos estén mejor pro­te­gi­dos.

De esta manera, cada vez que el usuario accede a recursos pro­te­gi­dos, como a una API o a una ruta protegida, el user agent utiliza el JWT como parámetro (por ejemplo, jwt para pe­ti­cio­nes GET) o como header de au­to­ri­za­ción (para POST, PUT, OPTIONS y DELETE). La otra parte puede descifrar el JSON Web Token y ejecutar la solicitud si la ve­ri­fi­ca­ción se realiza co­rre­c­ta­me­n­te.

Nota

Puesto que el JWT se basa en datos de inicio de sesión, no debe co­n­se­r­var­se nunca el token más tiempo del necesario ni almacenar ningún dato co­n­fi­de­n­cial en la memoria del navegador.

¿En qué casos se utiliza JSON Web Token?

JSON Web Token ofrece varias ventajas en co­m­pa­ra­ción con el método tra­di­cio­nal de au­te­n­ti­fi­ca­ción y au­to­ri­za­ción con cookies, por lo que se utiliza en las si­guie­n­tes si­tua­cio­nes:

  1. Apli­ca­cio­nes REST: En las apli­ca­cio­nes REST, el JWT garantiza la ausencia de estado enviando los datos de au­te­n­ti­fi­ca­ción di­re­c­ta­me­n­te con la petición.
  2. In­te­r­ca­m­bio de recursos de origen cruzado: JSON Web Token envía in­fo­r­ma­ción mediante el llamado cross-origin resource sharing, lo cual le da una gran ventaja sobre las cookies, que no suelen enviarse con este pro­ce­di­mie­n­to.
  3. Uso de varios fra­me­wo­r­ks: JSON Web Token está es­ta­n­da­ri­za­do y puede uti­li­zar­se una y otra vez. Cuando se emplean múltiples fra­me­wo­r­ks, los datos de au­te­n­ti­fi­ca­ción pueden co­m­pa­r­ti­r­se más fá­ci­l­me­n­te.

Ejemplo práctico de JWT

A co­n­ti­nua­ción, con un ejemplo de JWT, te mostramos el aspecto final de un token. Retomamos el header que me­n­cio­na­mos al principio:

{
	"alg": "HS256",
	"typ": "JWT"
}

El payload del JSON Web Token podría tener el siguiente aspecto:

{
	"sub": "0123456789",
	"name": "Juan Ejemplo",
	"admin": true
}

Para lograr la es­tru­c­tu­ra real del JWT (tres partes separadas por puntos), el header y el payload deben co­di­fi­car­se con Base64. La co­di­fi­ca­ción del header se rea­li­za­ría del siguiente modo:

base64Header = base64Encode(header)
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Lo mismo debe hacerse para el payload:

base64Payload = base64Encode(payload)
// eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

Ahora creamos la firma. En el header, indicamos que se firme con HMAC-SHA256:

signature = HS256(base64Header + '.' + base64Payload, 'secret')
// dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

Como último paso, estas tres partes deben unirse con puntos entre ellas:

Token = base64Header + '.' + base64Payload + '.' + signature
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

La mayoría de los lenguajes de pro­gra­ma­ción actuales pro­po­r­cio­nan bi­blio­te­cas para generar JWT, por lo que deja de ser necesaria la co­n­ve­r­sión manual.

Ir al menú principal