Skip to content

Instantly share code, notes, and snippets.

@DJDANNY123
Last active June 14, 2024 11:20
Show Gist options
  • Save DJDANNY123/7e597deab553ada6b68110e3ebcfa322 to your computer and use it in GitHub Desktop.
Save DJDANNY123/7e597deab553ada6b68110e3ebcfa322 to your computer and use it in GitHub Desktop.
K6 Subtle Webcrypto Jwt Signing, this simple example is for ES256 (ECDSA with the P-256 Elliptic Curve), but the same technique should be applicable with different keys
import {
describe,
expect,
// @ts-expect-error importing from url
} from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js';
import { crypto } from 'k6/experimental/webcrypto';
import {
encodeJwt,
printArrayBuffer,
string2ArrayBuffer,
} from './signing-utils.js';
export default async function () {
describe('can sign a jwt', async () => {
const keyPair = await crypto.subtle.generateKey(
{
name: 'ECDSA',
namedCurve: 'P-256',
},
true,
['sign', 'verify']
);
const result = await encodeJwt(
{ header: 'this is a header' },
{ claim: 'admin' },
keyPair.privateKey
);
// Should return a string with jwt structure
expect(result.split('.').length).to.equal(3);
});
describe('decodes a payload into the correct raw array', async () => {
// example payload encoding from https://www.ietf.org/archive/id/draft-jones-json-web-signature-03.html#rfc.appendix.Appendix%20A.3.1
const payload =
'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ';
const expected = [
101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 70, 85, 122, 73, 49, 78,
105, 74, 57, 46, 101, 121, 74, 112, 99, 51, 77, 105, 79, 105, 74, 113, 98,
50, 85, 105, 76, 65, 48, 75, 73, 67, 74, 108, 101, 72, 65, 105, 79, 106,
69, 122, 77, 68, 65, 52, 77, 84, 107, 122, 79, 68, 65, 115, 68, 81, 111,
103, 73, 109, 104, 48, 100, 72, 65, 54, 76, 121, 57, 108, 101, 71, 70,
116, 99, 71, 120, 108, 76, 109, 78, 118, 98, 83, 57, 112, 99, 49, 57, 121,
98, 50, 57, 48, 73, 106, 112, 48, 99, 110, 86, 108, 102, 81,
];
const result = printArrayBuffer(string2ArrayBuffer(payload));
expect(JSON.stringify(expected) == JSON.stringify(result)).to.equal(true);
});
}
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 printArrayBuffer = (buffer) => {
const view = new Uint8Array(buffer);
return Array.from(view);
};
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('.');
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment