Abe Estrada

AWS Lambda + JWT

En caso de necesitar validar un JWT (JSON Web Token) con AWS Lambda para alguna aplicaci贸n “serverless”, se puede realizar de la siguiente manera.

Primero hay que crear un folder, en este caso yo lo llam茅 jsonwebtoken y ejecute los siguientes comandos:

npm init -y
npm install jsonwebtoken --save

El archivo package.json qued贸 de la siguiente manera:

{
    "dependencies": {
        "jsonwebtoken": "^8.5.1"
    }
}

Luego hay que crear el paquete para poder subirlo a Lambda Layers.

zip -r jsonwebtoken-8.5.1.zip ./*

Me gusta agregar la versi贸n de la librer铆a que estoy utilizando en la descripci贸n para ser m谩s claro y llevar un mejor control.

Una vez creada esta capa (Layer), hay que agregarla a la funci贸n que vamos a utilizar para que pueda ser importada.

En este caso vamos a utilizar un JWT asim茅trico RS256 por lo que es necesario crear un par de llaves, una p煤blica y una privada

Para crear las llaves, se puede utilizar lo siguiente:

ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key
# No agregar passphrase
openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub

Luego hay que guardar de forma seguro la llave p煤blica (jwtRS256.key.pub) en Systems Manager / Parameter Store.

Ya listos los pasos anteriores, este es el c贸digo m铆nimo para poder verificar un JWT.

const AWS = require("aws-sdk");
AWS.config.update({ region: "us-east-1" });
const ssm = new AWS.SSM();

// From Lambda Layers
const jwt = require("/opt/node_modules/jsonwebtoken");

const getParameter = (param) => {
    return new Promise((resolve, reject) => {
        ssm.getParameter(param, (err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
    });
};

exports.handler = async (event) => {
    // Retrieve the encrypted parameter
    const publicKey = await getParameter({
        Name: "pubkey",
        WithDecryption: true,
    });
    // Verify JWT
    const body = jwt.verify(event.token, publicKey.Parameter.Value, (err, decoded) => {
        if (err) {
            return err;
        }
        return decoded;
    });
    const response = {
        statusCode: 200,
        body: JSON.stringify(body),
    };
    return response;
};

Lo que hace esa funci贸n es obtener la llave p煤blica encriptada del Systems Manager, luego utilizando la librer铆a jsonwebtoken verifica que el par谩metro token (en este caso, se puede utilizar cualquier otro m茅todo para obtener el JWT) sea un JWT v谩lido.

La misma librer铆a (jsonwebtoken) puede ser utilizada para generar un JWT para probar que funcione la funci贸n creada, solo hay que pasar el token generado.

const fs = require("fs");
const jwt = require("jsonwebtoken");

const privateKey = fs.readFileSync("./jwtRS256.key");

jwt.sign({ hello: "world" }, privateKey, { algorithm: "RS256", expiresIn: "1h" }, (err, token) => {
    console.log(token);
});