Auth con JWT y Express.js
Auth con JWT y Express.js — RO Solutions Blog
La mayoría de las aplicaciones que utilizamos manejan autentificación. Muchas de estas aplicaciones ofrecen acceso por medio de aplicaciones de terceros como Facebook, Google, Twitter, este tipo de autentificación se conoce como OAuth, o el fiel combo correo-contraseña. Porque menciono esto, estas aplicaciones comparten la misma estrategia o método de verificar al usuario con el servidor que desean consultar, este método se conoce como JWT. JWT (JSON Web Tokens) es un estándar de autentificación, que se encuentra estandarizado por el IETF en RFC7519, que tiene como función identificar al usuario que solicita peticiones a nuestro servidor. Es muy diferente a una session/cookie, el token encriptado del usuario se envía por cada petición que el cliente haga, y el servidor se encarga de verificar el token que recibió. Los JWT están conformados por un header, un payload, y un signature.
Header muestra el algoritmo de hash que se utilizó.
Payload contiene información pública y privada del token (fecha de expiración, fecha de creación, información del usuario).
Signature es para verificar si el cliente es quien dice ser.
Ejemplo de un JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
La estrategia que nosotros utilizaremos para la verificar las peticiones a nuestro servidor será verificar el JWT que nos envíe nuestro cliente por el HTTP Authorization Header, así el cliente podrá acceder a los recursos que ofrezca nuestro servidor. Express es un web framework de Node.js que nos ayudará a crear un REST API básico y rápido, con middleware y rutas, para que nuestros clientes la consuman. Bien! Ahora que tenemos un concepto claro de que hace cada herramienta, tenemos que planear y crear los flujos de nuestra API. Primero crearemos una carpeta donde contenga nuestra aplicación, crearemos un archivo de extensión js e instalaremos nuestras dependencias:
mkdir jwt-pass && cd jwt-pass
touch index.js usuarios.json .env
npm init -y
npm i -S dotenv uuid express cors bcryptjs jsonwebtoken body-parser
Después modificaremos el .env con variables de entorno para nuestra aplicación: HOST=0.0.0.0 PORT=3000 JWT_SECRET=cruelcruelworldmustIgooncruelcruelworldImmovingon Después tenemos que modificar el archivo base de la aplicación, el index.js.
require('dotenv').config();
const fs = require('fs');
const http = require('http');
const cors = require('cors');
const uuidv4 = require('uuid/v4');
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');
const salt = 10;
const host = process.env.HOST || '127.0.0.1';
const port = process.env.PORT || 3000;
const secret = process.env.JWT_SECRET || 'NeverTellYourSecrets';
const app = express();
const server = http.createServer(app);
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.get('/info', (req, res) => res.json('Hiya buddy!'));
server.listen(port, host, () => {
console.log(`jwt-pass app listening on ${host}:${port}`);
});
Para registrar usuarios, agregamos la función de utilidades y la ruta /signup:
let listaUsuarios = (() => {
try {
return JSON.parse(fs.readFileSync('./usuarios.json', 'utf8'));
} catch (error) {
return [];
}
})();
const updateUsuarios = obj => fs.writeFileSync('./usuarios.json', JSON.stringify(obj), 'utf8');
const hashPassword = async (pwd) => {
try {
return await bcrypt.hash(pwd, salt);
} catch (error) {
throw error;
}
};
Después crearemos la ruta /login para entregar un JWT válido:
const verifyJWT = token => jwt.verify(token, secret);
const checkJWT = (req, res, next) => {
try {
const { authorization } = req.headers;
const decoded = verifyJWT(authorization.split(' ')[1]);
const [usuario] = listaUsuarios.filter(u => u.id === decoded.id);
if (!usuario || !usuario.activo) throw Error();
req.usuario = usuario;
next();
} catch (error) {
return res.status(401).send({ message: 'Unauthorized' });
}
};
app.get('/info', checkJWT, (req, res) => res.json(req.usuario));
Si gustan ver que header, payload y signature contiene su token, pueden debuggearlo en la página oficial de JWT. Cualquier duda o sugerencia, me la pueden hacer saber. Hasta la próxima, vaqueros!
