Last active
March 27, 2025 17:09
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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