Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JWT signing with k6

How could I encode a JSON object with a JWT signature with k6?

export default function() {

  const mySecret = "aaaaaaa";
  const token = jwt.encode({ foo: 'bar' }, mySecret);

}
like image 833
ppcano Avatar asked Nov 02 '25 01:11

ppcano


2 Answers

You can use the builtin k6/encoding and k6/crypto modules to work with JWTs.

Since the k6/crypto module doesn't yet support public-key cryptography you can only use shared secrets to sign your JWTs (without doing crypto in pure JS).

Here's an example script:

import crypto from "k6/crypto";
import encoding from "k6/encoding";

const algToHash = {
    HS256: "sha256",
    HS384: "sha384",
    HS512: "sha512"
};

function sign(data, hashAlg, secret) {
    let hasher = crypto.createHMAC(hashAlg, secret);
    hasher.update(data);

    // Some manual base64 rawurl encoding as `Hasher.digest(encodingType)`
    // doesn't support that encoding type yet.
    return hasher.digest("base64").replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
}

function encode(payload, secret, algorithm) {
    algorithm = algorithm || "HS256";
    let header = encoding.b64encode(JSON.stringify({ typ: "JWT", alg: algorithm }), "rawurl");
    payload = encoding.b64encode(JSON.stringify(payload), "rawurl");
    let sig = sign(header + "." + payload, algToHash[algorithm], secret);
    return [header, payload, sig].join(".");
}

function decode(token, secret, algorithm) {
    let parts = token.split('.');
    let header = JSON.parse(encoding.b64decode(parts[0], "rawurl"));
    let payload = JSON.parse(encoding.b64decode(parts[1], "rawurl"));
    algorithm = algorithm || algToHash[header.alg];
    if (sign(parts[0] + "." + parts[1], algorithm, secret) != parts[2]) {
        throw Error("JWT signature verification failed");
    }
    return payload;
}

export default function() {
    let message = { key2: "value2" };
    let token = encode(message, "secret");
    console.log("encoded", token);
    let payload = decode(token, "secret");
    console.log("decoded", JSON.stringify(payload));
}
like image 107
Robin Gustafsson Avatar answered Nov 04 '25 17:11

Robin Gustafsson


There's now support in k6/experimental/webcrypto which provides utility functions to encode and sign JWTs. I've created a simple example for using this to sign a JWT using the new support for Elliptic Curve cryptography as of k6 v0.51.0:

import { CryptoKey, crypto } from 'k6/experimental/webcrypto';
import encoding from 'k6/encoding';

export const string2ArrayBuffer = (str: string) => {
  const buf = new ArrayBuffer(str.length);
  const bufView = new Uint8Array(buf);
  for (let i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
};


export const encodeJwt = async (
  header: Object,
  payload: Object,
  key: CryptoKey
) => {
  const headerString = encoding.b64encode(JSON.stringify(header), 'rawurl');
  const payloadString = encoding.b64encode(JSON.stringify(payload), 'rawurl');

  const signatureBuffer = await crypto.subtle.sign(
    {
      name: 'ECDSA',
      hash: 'SHA-256',
    },
    key,
    string2ArrayBuffer([headerString, payloadString].join('.'))
  );

  const signature = encoding.b64encode(signatureBuffer, 'rawurl');

  return [headerString, payloadString, signature].join('.');
};

Full GIST: https://gist.github.com/DJDANNY123/7e597deab553ada6b68110e3ebcfa322#file-signing-utils-ts

like image 27
Danny Jackson Avatar answered Nov 04 '25 17:11

Danny Jackson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!