I was messing around with dgraph lambdas for a side project and wanted to issue JWTs from this lambda (more or less to hide the secret used to sign with) and it took me a long time to get something to work. I am mostly a golang programmer these days so javascript was super annoying for me… but I wanted to share what I had in case it helps someone else save a few hours.
(disclaimer: no warranty, no support, no liability, not security advice)
const hdr = {"alg": "HS256","typ": "JWT"}
const tokenExpirySeconds = 900
// not to be registered directly as a lambda but called from a lambda registered function
async function CreateAndSignJWTWithClaims(claims, secretKey) {
const now = ~~(Date.now()/1000)
claims.iat=now
claims.exp=now+tokenExpirySeconds
const unsignedToken = base64url(JSON.stringify(hdr)) + "." + base64url(JSON.stringify(claims))
const key = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(secretKey),
{name: "HMAC", hash: "SHA-256" },
false,
["sign"]
)
const sig = await crypto.subtle.sign(
{name:"HMAC"},
key,
new TextEncoder().encode(unsignedToken)
)
return unsignedToken + "." + base64url(_arrayBufferToBinary(sig))
}
// this is used to change standard base64 to jwt-ready base64. Adapted from stackoverflow
function base64url(source) {
encodedSource = btoa(source)
encodedSource = encodedSource.replace(/=+$/, '')
encodedSource = encodedSource.replace(/\+/g, '-')
encodedSource = encodedSource.replace(/\//g, '_')
return encodedSource
}
// this is modified from stackoverflow "how to turn an ArrayBuffer into an Uint8Array"
// I really hope there is some other way to do this....
function _arrayBufferToBinary( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return binary ;
}
Again, I do not know if there is a better way to do this, but I wanted a thing that would sign a jwt without using webpack. Sorry if there is already a better snippet out there that does this. The above will make a JWT that is usable with dgraph given the secretKey given as the VerificationKey in the annotation:
# Dgraph.Authorization {"VerificationKey":"SECRETKEY","Algo":"HS256"}
Also, for the record, javascript is infuriating.