Skip to content

Instantly share code, notes, and snippets.

@mattmazzola
Last active May 10, 2023 12:06
Show Gist options
  • Save mattmazzola/1eafd7aea79e082982da203ec0405997 to your computer and use it in GitHub Desktop.
Save mattmazzola/1eafd7aea79e082982da203ec0405997 to your computer and use it in GitHub Desktop.
jwt-simple-browser
function createToken(payload, key) {
var header = { typ: 'JWT', alg: 'HS256' };
var segments = [];
segments.push(encodeURIComponent(btoa(JSON.stringify(header))));
segments.push(encodeURIComponent(btoa(JSON.stringify(payload))));
var footer = sign(segments.join('.'), key);
segments.push(footer);
return segments.join('.');
}
function sign(data, key) {
window.crypto.subtle.importKey(
"jwk", //can be "jwk" or "raw"
{ //this is an example jwk key, "raw" would be an ArrayBuffer
kty: "oct",
k: key,
alg: "HS256",
ext: true,
},
{ //this is the algorithm options
name: "HMAC",
hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
//length: 256, //optional, if you want your key length to differ from the hash function's block length
},
true, //whether the key is extractable (i.e. can be used in exportKey)
["sign", "verify"] //can be any combination of "sign" and "verify"
)
.then(key => {
var jsonString = JSON.stringify(data);
var encodedData = new TextEncoder().encode(jsonString);
return window.crypto.subtle.sign(
{
name: "HMAC",
},
key, //from generateKey or importKey above
encodedData //ArrayBuffer of data you want to sign
);
})
.then(token => {
var u8 = new Uint8Array(token);
var b64encoded = btoa(String.fromCharCode.apply(null, u8));
console.log(`token: `, b64encoded);
return b64encoded;
});
}
var claims = { a: 1 };
createToken(claims, "ELZ99QBzWjrFyNIPu5cancZQ/j8WbRK8OwrckoUE7nyibzyLh1kHzckamu3VlN+egNL8DERMnHkG5BzJwSwG4Q==");
@ehuggett
Copy link

From your issue that linked to this gist

When attempting to import the key I am receiving the error:
undefined:1 Uncaught (in promise) DOMException: The JWK member "k" could not be base64url decoded or contained padding

I know the trailing equal signs indicate there is padding on the key ==, but I'm not sure how to remove it and still import using the same method.

key = key.replace(/=/g,'') ?

I have been importing keys in python that were generated/exported with the webcrypto api and I had the opposite problem, I had to put the padding back to use pythons base64.urlsafe_b64decode()! .

@Jehong-Ahn
Copy link

Thanks.

You should try base64url encode for jwt spec.

function encodeBase64Url (data) {
  return btoa(data).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment