Inicio de sesión

Autenticación sencilla basada en tokens

Aprende sobre la autenticación basada en tokens y cómo implementar fácilmente JWT en tus aplicaciones.

token-based-authentication-made-easy

Autenticación basada en tokens

Un token es un dato que no tiene significado ni utilidad por sí mismo, pero que combinado con el sistema de tokenización correcto, se convierte en un elemento vital para asegurar tu aplicación. La autenticación basada en tokens funciona garantizando que cada solicitud a un servidor vaya acompañada de un token firmado cuya autenticidad verifica el servidor y solo entonces responde a la solicitud.

JSON Web Token (JWT) es un estándar abierto (RFC 7519) que define un método compacto y autocontenido para la transmisión segura de información entre partes codificadas como un objeto JSON. JWT ha ganado popularidad masiva debido a su tamaño compacto, que permite que los tokens se transmitan fácilmente a través de cadenas de consulta, atributos de encabezado y dentro del cuerpo de una solicitud POST.

¿Estás interesado en ponerte al día con JWT lo antes posible? DESCARGAR EL EBOOK GRATUITO

¿Por qué utilizar tokens?

El uso de tokens tiene muchas ventajas en comparación con métodos tradicionales como las cookies.

  • Los tokens no tienen estado. El token es autónomo y contiene toda la información necesaria para la autenticación. Esto es genial para la escalabilidad, ya que libera a tu servidor de tener que almacenar el estado de la sesión.
  • Los tokens pueden generarse desde cualquier lugar. La generación de tokens está desacoplada de la verificación de tokens, lo que te permite la opción de gestionar la firma de tokens en un servidor independiente o incluso a través de una empresa diferente, como Auth0.
  • Control de acceso detallado. Dentro de la carga útil del token, puedes especificar fácilmente las funciones y permisos del usuario, así como los recursos a los que puedes acceder.

Estas son solo algunas de las ventajas que ofrecen los tokens web JSON. Para obtener más información, consulta esta entrada del blog que profundiza en el tema y compara los tokens con las cookies para gestionar la autenticación.

Anatomía de un token web JSON

Un token web JSON consta de tres partes: Encabezado, Carga útil y Firma. El encabezado y la carga útil se codifican en Base64, luego se concatenan con un punto y, finalmente, el resultado se firma algorítmicamente produciendo un token en forma de header.claims.signature. El encabezado consta de metadatos que incluyen el tipo de token y el algoritmo hash utilizado para firmar el token. La carga útil contiene los datos de las reclamaciones que codifica el token. El resultado final es el siguiente:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtZXNzYWdlIjoiSldUIFJ1bGVzISIsImlhdCI6MTQ1OTQ0ODExOSwiZXhwIjoxNDU5NDU0NTE5fQ.-yIVBD5b73C75osbmwwshQNRC7frWUYrqaTjTpza2y4

Los tokens se firman para protegerlos de manipulaciones, no se cifran. Esto significa que una ficha puede decodificarse fácilmente y revelar su contenido. Si navegamos sobre el jwt.io y pegamos el token anterior, podremos leer el encabezado y la carga útil, pero sin el secreto correcto, el token es inútil y vemos el mensaje “Firma no válida”. Si añadimos el secreto correcto, en este ejemplo, la cadena L3@RNJWT, ahora veremos un mensaje que dice “Firma verificada”.

Decodificación de un JWT con JWT.io

En una situación real, un cliente haría una petición al servidor y pasaría el token con la petición. El servidor intentaría verificar el token y, si tiene éxito, continuaría procesando la solicitud. Si el servidor no pudiera verificar el token, el servidor enviaría un 401 No Autorizado y un mensaje diciendo que la solicitud no pudo ser procesada ya que la autorización no pudo ser verificada.

Prácticas recomendadas para tokens web JSON

Antes de llegar a la implementación de JWT, vamos a cubrir algunas de las prácticas recomendadas para garantizar que la autenticación basada en tokens se implemente correctamente en tu aplicación.

  • Mantenerlo en secreto. Mantenerlo a salvo. La clave de firma debe tratarse como cualquier otra credencial y revelarse solo a los servicios que la necesiten absolutamente.
  • No añadir datos sensibles a la carga útil. Los tokens están firmados para protegerlos de manipulaciones y son fáciles de decodificar. Añada el mínimo número de reclamaciones a la carga útil para obtener el mejor rendimiento y seguridad.
  • Establecer una caducidad para los tokens. Técnicamente, una vez firmado un token, es válido para siempre, a menos que se cambie la clave de firma o se establezca explícitamente su caducidad. Esto podría plantear problemas potenciales, por lo que hay que tener una estrategia de caducidad o revocar los tokens.
  • Adoptar HTTPS No envíes tokens a través de conexiones que no sean HTTPS, ya que esas solicitudes pueden ser interceptadas y los tokens pueden quedar comprometidos.
  • Considerar todos los casos de uso de la autorización. Añadir un sistema de verificación de tokens secundario que garantice que los tokens se generaron desde su servidor, por ejemplo, puede no ser una práctica habitual, pero puede ser necesario para satisfacer tus requisitos.

Para obtener más información y conocer las mejores prácticas, visita la entrada del blog 10 cosas que debes saber sobre los tokens.

Autenticación sencilla basada en tokens

La autenticación basada en tokens y JWT son ampliamente compatibles. JavaScript, Python, C#, Java, PHP, Ruby, Go y otros disponen de bibliotecas para firmar y verificar fácilmente tokens web JSON. Implementemos una API y veamos lo rápido que podemos asegurarla con JWT.

Hemos optado por construir nuestra API con NodeJS, ya que requiere la menor cantidad de configuración. Echemos un vistazo al código de nuestra implementación de JWT.

// Cargar en nuestras dependencias
var express = require('express');
var jwt = require('jsonwebtoken');

var app = express();

// Registrar la ruta de inicio que muestra un mensaje de bienvenida
// Se puede acceder a esta ruta sin token
app.get('/', function(req, res){
  res.send('Welcome to our API');
})

// Registrar la ruta para obtener un nuevo token
// En una situación real autenticaríamos las credenciales del usuario
// antes de crear un token, pero para simplificar el acceso a esta ruta
// generará un nuevo token válido durante 2 minutos
app.get('/token', function(req, res){
  var token = jwt.sign({username:'ado'}, 'supersecret',{expiresIn: 120});
  res.send(token)
})

// Registrar una ruta que requiera un token válido para ver los datos
app.get('/api', function(req, res){
  var token = req.query.token;
  jwt.verify(token, 'supersecret', function(err, decoded){
    if(!err){
      var secrets = {'accountNumber' : '938291239','pin' : '11289','account' : 'Finance'};
      res.json(secrets);
    } else {
      res.send(err);
    }
  })
})

// Iniciar nuestra aplicación en el puerto 3000
app.listen('3000');

Para probar nuestra API actual, vamos a ejecutar la aplicación y navegar a localhost:3000. Solo veremos el mensaje “Bienvenido a nuestra API”. A continuación, navega a la ruta localhost:3000/api y veremos un mensaje de error JWT que dirá que no hemos obtenido un token. Vaya a la ruta localhost:3000/token y verá que se ha generado un nuevo token. Copie este token, luego navegue a localhost:3000/api?token={ADD-COPIED-TOKEN-HERE} y verá la respuesta prevista que son las cuentas financieras de la empresa.

Con solo unas pocas líneas de código fuimos capaces de asegurar nuestro punto de conexión de API. No cubrimos el manejo adecuado de la autenticación del usuario antes de generar un token. A continuación, lo haremos con Auth0.

Autenticación de JWT escalonada con Auth0

Necesitaremos hacer algunas ligeras modificaciones a nuestro código para mostrar el flujo de autenticación con Auth0. Examinemos los cambios a continuación:

// Cargar en nuestras dependencias
var express = require('express');
var jwt = require('express-jwt');

var jwtCheck = jwt({
  secret: new Buffer('{YOUR-APP-SECRET}', 'base64'),
  audience: '{YOUR-APP-CLIENT-ID}'
});

var app = express();

// En lugar de buscar un token en nuestro controlador
// usaremos un software intermedio para que si el token no es válido podamos
// detener la ejecución de la solicitud
app.use('/api', jwtCheck);

app.get('/', function(req, res){
  res.send('Welcome to our API');
})

app.get('/api', function(req, res){
  var secrets = {'accountNumber' : '938291239','pin' : '11289','account' : 'Finance'};
  res.json(secrets);
})

app.listen('3000');

Para probar que esto funciona, vamos a iniciar el servidor y navegar a localhost:3000/api. Vemos un mensaje diciendo que no enviamos un token de autorización. Dirijámonos a Auth0 Playground, agreguemos nuestras credenciales y obtengamos un token. Añade el siguiente código en la página de pruebas de configuración:

var domain = '{YOUR-AUTH0-DOMAIN}.auth0.com';
var clientID = '{YOUR-APP-CLIENT-ID}';

var lock = new Auth0Lock(clientID, domain);
lock.show({
  focusInput: false,
  popup: true,
}, function (err, profile, token) {
  alert(token)
});

Para asegurarnos de que podemos obtener un token, necesitaremos navegar a la configuración de nuestra aplicación en el Panel de control de Auth0 y agregar https://auth0.github.io/playground a nuestra lista de URL de retorno de llamadas permitidas. Ahora, vamos a iniciar sesión o crear una cuenta en Auth0 Playground y obtendremos una ventana emergente que revela nuestro token.

Para comprobar el contenido de nuestro token, podemos decodificarlo en jwt.io. Para verificar el token, necesitaremos el Client Secret de nuestra aplicación de Auth0 y tendremos que marcar la casilla secret base64 encode. Luego de hacer esto, deberíamos ver el mensaje “Firma verificada”.

Para probar que nuestra API funciona con este token, tenemos que hacer una petición GET a localhost:3000/api y enviar el token en un encabezado de Autorización. La forma más sencilla de hacerlo es utilizar una aplicación como Postman, que simplifica las pruebas de los puntos finales de la API. Al realizar la llamada, añade un encabezado de Autorización, y para el valor, añade Bearer {TOKEN}. Cuando se realiza la llamada, el software intermedio jwtCheck examinará la solicitud, se asegurará de que tenga el encabezado de Autorización en el formato correcto, extraerá el token, lo verificará y, si se verifica, procesará el resto de la solicitud. Hemos utilizado solo la configuración por defecto para mostrar las capacidades de JWT, pero puedes aprender mucho más a través de los documentos.

Casos de uso de la autenticación basada en tokens

Hemos visto lo fácil que es implementar la autenticación de JWT y asegurar nuestra API. Para terminar, examinemos los casos de uso para los que es más adecuada la autenticación basada en tokens.

  • Aplicaciones de plataforma como servicio: exposición de API RESTful que serán consumidas por diversos marcos y clientes.
  • Aplicaciones móviles: implementación de aplicaciones móviles nativas o híbridas que interactúan con tus servicios.
  • Aplicaciones de página única (SPA): creación de aplicaciones modernas con marcos como Angular y React.

Para obtener más información sobre cómo empezar a utilizar tokens web JSON, consulta este artículo.

Regístrese gratis

Empiece a construir hoy mismo y proteja sus aplicaciones con la plataforma de identidad Auth0.

3D login box