I am trying to create a signed JWT in postman with the following code
function base64url(source) {
// Encode in classical base64
encodedSource = CryptoJS.enc.Base64.stringify(source);
// Remove padding equal characters
encodedSource = encodedSource.replace(/=+$/, '');
// Replace characters according to base64url specifications
encodedSource = encodedSource.replace(/\+/g, '-');
encodedSource = encodedSource.replace(/\//g, '_');
return encodedSource;
}
function addIAT(request) {
var iat = Math.floor(Date.now() / 1000) + 257;
data.iat = iat;
return data;
}
var header = {
"typ": "JWT",
"alg": "HS256"
};
var data = {
"fname": "name",
"lname": "name",
"email": "[email protected]",
"password": "abc123$"
};
data = addIAT(data);
var secret = 'myjwtsecret';
// encode header
var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
var encodedHeader = base64url(stringifiedHeader);
// encode data
var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data));
var encodedData = base64url(stringifiedData);
// build token
var token = encodedHeader + "." + encodedData;
// sign token
var signature = CryptoJS.HmacSHA256(token, secret);
signature = base64url(signature);
var signedToken = token + "." + signature;
postman.setEnvironmentVariable("payload", signedToken);
Code taken from https://gist.github.com/corbanb/db03150abbe899285d6a86cc480f674d .
I've been trying to input the PEM as the secret but does not work. Also can't find any HmacSHA256 overload that takes a PEM.
How can that be done?
JSON Web Token is an open standard for securely transferring data within parties using a JSON object. JWT is used for stateless authentication mechanisms for users and providers, this means maintaining session is on the client-side instead of storing sessions on the server.
The mention of postman changed this. I have a solution for you, but it's not exactly a clean way by any mean.
You'll need to create a request that you will need to execute whenever you open postman. Go as follows:
The purpose of this request is to side-load jsrsasign-js
and storing it in a global Postman variable.
Once this is done, you can then use this content elsewhere. For every request you need a RSA256 JWT signature, the following pre-request script will update a variable (here, token
) with the token:
var navigator = {};
var window = {};
eval(pm.globals.get("jsrsasign-js"));
function addIAT(request) {
var iat = Math.floor(Date.now() / 1000) + 257;
data.iat = iat;
return data;
}
var header = {"alg" : "RS256","typ" : "JWT"};
var data = {
"fname": "name",
"lname": "name",
"email": "[email protected]",
"password": "abc123$"
};
data = addIAT(data);
var privateKey = "-----BEGIN RSA PRIVATE KEY----- \
MIIBOQIBAAJAcrqH0L91/j8sglOeroGyuKr1ABvTkZj0ATLBcvsA91/C7fipAsOn\
RqRPZr4Ja+MCx0Qvdc6JKXa5tSb51bNwxwIDAQABAkBPzI5LE+DuRuKeg6sLlgrJ\
h5+Bw9kUnF6btsH3R78UUANOk0gGlu9yUkYKUkT0SC9c6HDEKpSqILAUsXdx6SOB\
AiEA1FbR++FJ56CEw1BiP7l1drM9Mr1UVvUp8W71IsoZb1MCIQCKUafDLg+vPj1s\
HiEdrPZ3pvzvteXLSuniH15AKHEuPQIhAIsgB519UysMpXBDbtxJ64jGj8Z6/pOr\
NrwV80/EEz45AiBlgTLZ2w2LjuNIWnv26R0eBZ+M0jHGlD06wcZK0uLsCQIgT1kC\
uNcDTERjwEbFKJpXC8zTLSPcaEOlbiriIKMnpNw=\
-----END RSA PRIVATE KEY-----";
var sHeader = JSON.stringify(header);
var sPayload = JSON.stringify(data);
var sJWT = KJUR.jws.JWS.sign(header.alg, sHeader, sPayload, privateKey);
pm.variables.set('token', sJWT);
In order:
window
and navigator
objects as jsrsasign-js
needs them.eval()
the content of what we fetched earlier in order to rehydrate everythingjsrsasign-js
. Your token info is there, and I've defined a private key there. You can change this or use an environment variable; it's just there for demo purposes. I then simply use the rehydrated library to sign it, and set the variable to the value of the signed JWT.A PEM
, as you refer to it, is a container format specifying a combination of public and/or private key. You're using it to sign using HMAC-SHA256
, which operates on a shared secret. This obviously isn't going to work (unless you take the poor man's approach and use your public key as the shared secret).
Fortunately enough, there are other signature methods defined in the RFCs. For instance, there is a way to sign using RSA
, and a very convenient way of defining a public key as a JSON web key (JWK
). We're going to be leveraging both.
I've generated a key pair for testing, they're named out
and out.pub
. Generation tool is genrsa
(and as such, they're an RSA keypair).
In order to sign, we're going to have to change a few things:
HS256
to RS256
, as explained abovecrypto-js
does not support asymmetric key crypto. We'll fall back to the native crypto
module, though there are pure-JS alternativesThe code:
var CryptoJS = require("crypto-js");
var keyFileContent = require("fs").readFileSync("./out");
var pubkey = require("fs").readFileSync("./out.pub");
var base64url = require("base64url");
var nJwt = require("njwt");
function addIAT(request) {
var iat = Math.floor(Date.now() / 1000) + 257;
data.iat = iat;
return data;
}
var header = {
"typ": "JWT",
"alg": "RS256"
};
var data = {
"fname": "name",
"lname": "name",
"email": "[email protected]",
"password": "abc123$"
};
data = addIAT(data);
// encode header
var stringifiedHeader = JSON.stringify(header);
var encodedHeader = base64url(stringifiedHeader);
// encode data
var stringifiedData = JSON.stringify(data);
var encodedData = base64url(stringifiedData);
// build token
var token = encodedHeader + "." + encodedData;
// sign token
var signatureAlg = require("crypto").createSign("sha256");
signatureAlg.update(token);
var signature = signatureAlg.sign(keyFileContent);
signature = base64url(signature);
var signedToken = token + "." + signature;
console.log(signedToken);
// Verify
var verifier = new nJwt.Verifier();
verifier.setSigningAlgorithm('RS256');
verifier.setSigningKey(pubkey);
verifier.verify(signedToken, function() {
console.log(arguments);
});
And that's it! It's quite literally that simple, although I would not recommend rewriting the sign()
function from crypto
from scratch. Leave it to a library that has had thorough inspection by the community, and crypto is pretty serious business.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With