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#domain.com",
"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?
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#domain.com",
"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:
I define mock window and navigator objects as jsrsasign-js needs them.
I then eval() the content of what we fetched earlier in order to rehydrate everything
The rest of your code is simple usage of jsrsasign-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:
We're changing algorithms from HS256 to RS256, as explained above
We're going to need a new library to do the signing itself, as crypto-js does not support asymmetric key crypto. We'll fall back to the native crypto module, though there are pure-JS alternatives
The 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#domain.com",
"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.
Related
I am working on a script to dynamically create a JWT for a google api call when a customer record is edited/created in NetSuite. I have been able to successfully call the api from a script with a manually created JWT. This script will create a new JWT for every call, this is needed because a JWT is only active for 1 hour after creation, the issue I am running into is correctly encoding an object. The documentation I found on SuiteAnswers only referenced encoding strings, and I am not totally sure how the encoding process works when done manually. (if the entire object is stringified or if it is broken up)
This is the piece of code with the object (payload) needing to be encoded correctly to finish creating the JWT.
var secondsSinceEpoch = Math.round(Date.now() / 1000)
var plusOneHour = secondsSinceEpoch + 3600
var payload = {
"target_audience": "https://sample.com",
"iss": "sample.com",
"sub": "sample.com",
"exp": plusOneHour,
"iat": secondsSinceEpoch,
"aud": "https://www.googleapis.com/oauth2/v4/token"
}
log.debug({
title:'payload',
details: JSON.stringify(payload)});
var base64EncodedString = encode.convert({
string: JSON.stringify(payload),
inputEncoding: encode.Encoding.UTF_8,
outputEncoding: encode.Encoding.BASE_64_URL_SAFE});
return connectToGCP(base64EncodedString)```
If you don't have to use public/private keys for signing your solution would look something like:
/**
*#NApiVersion 2.x
*/
define(['N/encode', 'N/crypto'], function(encode, crypto){
function signIt(payload, ttl){
if(typeof payload.exp == 'undefined'){
var secondsSinceEpoch = Math.round(Date.now() / 1000);
var expAt = secondsSinceEpoch + (ttl || 60);
payload["exp"] = expAt;
payload["iat"] = secondsSinceEpoch;
}
log.debug({
title:'payload',
details: JSON.stringify(payload)});
function toB64(str){
return encode.convert({
string: str,
inputEncoding: encode.Encoding.UTF_8,
outputEncoding: encode.Encoding.BASE_64_URL_SAFE}).replace(/=+$/, '');
}
var header = toB64(JSON.stringify({
type:'JWT',
alg:'HS256'
}));
var body = toB64( JSON.stringify(payload));
var mySecret = 'custsecret_jwt_sample_secret'; //secret id take from secrets management page
var sKey = crypto.createSecretKey({
secret: mySecret,
encoding: encode.Encoding.UTF_8
});
var signer = crypto.createHmac({
algorithm: crypto.HashAlg.SHA256,
key:sKey
});
signer.update({
input:header +'.'+ body,
inputEncoding: encode.Encoding.UTF_8
});
var sig = signer.digest({
outputEncoding:encode.Encoding.BASE_64_URL_SAFE
}).replace(/=+$/, '');
return [header, body, sig].join('.');
}
return {
signIt: signIt
}
});
I wrote an interface to make requests to the internal audible api with python. Every API request needs to be signed with RSA SHA256.
Now I want to test the endpoints of the API with Postman and make use of the pre request script function. But I'm not firm with javascript. Maybe someone can help me in translate the following python function to a Postman script:
def sign_request(
request: httpx.Request, adp_token: str, private_key: str
) -> httpx.Request:
"""
Helper function who creates a signed requests for authentication.
:param request: The request to be signed
:param adp_token: the token is obtained after register as device
:param private_key: the rsa key obtained after register as device
:returns: The signed request
"""
method = request.method
path = request.url.path
query = request.url.query
body = request.content.decode("utf-8")
date = datetime.utcnow().isoformat("T") + "Z"
if query:
path += f"?{query}"
data = f"{method}\n{path}\n{date}\n{body}\n{adp_token}"
key = rsa.PrivateKey.load_pkcs1(private_key.encode())
cipher = rsa.pkcs1.sign(data.encode(), key, "SHA-256")
signed_encoded = base64.b64encode(cipher)
signed_header = {
"x-adp-token": adp_token,
"x-adp-alg": "SHA256withRSA:1.0",
"x-adp-signature": f"{signed_encoded.decode()}:{date}"
}
request.headers.update(signed_header)
return request
I found out how to get the request method and the body. I can get the path and query with pm.request.url.getPathWithQuery(). To add the headers to the request I use pm.request.headers.add.
But I doesn't know how to get the datetime in isoformat, join strings and sign the data.
I'm get it running with the pm lib. Thank you for your help.
The only issue is getting the private cert, who contains newlines, from env var gives an error with these code sig.init(privateKey);. I had to write the private cert string directly in the pre request script.
Here are my script.
eval( pm.globals.get('pmlib_code') );
var CryptoJS = require("crypto-js");
var moment = require("moment");
const adpToken = pm.environment.get("adp-token")
// private-key loaded from env var doesn't work because of newlines in it; bugfix
const privateKey = pm.environment.get("private-key")
// use private-key in pre request script directly make use of newline correctly
const privateKey2 = "-----BEGIN RSA PRIVATE KEY-----\nMIIE...==\n-----END RSA PRIVATE KEY-----\n"
signRequest(pm.request, adpToken, privateKey);
function signRequest(request, adpToken, privateKey2) {
const method = request.method;
const path = request.url.getPathWithQuery();
const body = request.body || "";
const date = moment.utc().format();
const data = `${method}\n${path}\n${date}\n${body}\n${adpToken}`;
var sig = new pmlib.rs.KJUR.crypto.Signature({"alg": "SHA256withRSA"});
sig.init(privateKey);
var hash = sig.signString(data);
const signedEncoded = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(hash));
pm.request.headers.add({
key: 'x-adp-token',
value: adpToken
});
pm.request.headers.add({
key: 'x-adp-alg',
value: 'SHA256withRSA:1.0'
});
pm.request.headers.add({
key: 'x-adp-signature',
value: `${signedEncoded}:${date}`
});
}
UPDATE:
Now reading the device cert from env var works. I had to replace const privateKey = pm.environment.get("private-key") with const privateKey = pm.environment.get("private-key").replace(/\\n/g, "\n")
The problem to make this in Postman is that you can use only those packages available in sandbox. So for this, you have crypto-js as the unique package helper for crypto operations.
var CryptoJS = require("crypto-js");
var moment = require("moment");
signRequest(pm.request, "yourAdpToken", "yourPrivateKey")
function signRequest(request, adpToken, privateKey) {
const method = request.method;
const path = request.url.getPathWithQuery();
const body = request.body.raw;
const date = moment.utc().format();
const data = `${method}\n${path}\n${date}\n${body}\n${adpToken}`
const hash = CryptoJS.HmacSHA256(data, privateKey);
const signedEncoded = CryptoJS.enc.Base64.stringify(hash);
pm.request.headers.add({
key: 'x-adp-token',
value: adpToken
});
pm.request.headers.add({
key: 'x-adp-alg',
value: 'SHA256withRSA:1.0'
});
pm.request.headers.add({
key: 'x-adp-signature',
value: `${CryptoJS.enc.Base64.parse(signedEncoded)}:${date}`
});
}
Adding the above to the Pre-request Script will add your wanted headers to the request like this:
You may need to change the encode parts, check the encode options
I have been trying to communicate with the private API on kraken. The error I get suggests {"error":["EAPI:Invalid key"]} that the encryption/decryption steps are correct. I have tried creating new keys, does not help. I'm wondering if the 'format' of the signature variable is wrong, even though correct in nature.
function balance () {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("API_read_only");
var key = sheet.getRange("B5").getValue()
var secret = sheet.getRange("B6").getValue()
// (API method, nonce, and POST data)
var path = "/0/private/TradeBalance"
var nonce = new Date () * 1000
var postdata = "nonce=" + nonce
//Algorithms
//Calculate the SHA256 of the nonce and the POST data
// using goolge script lib
// using more succint function from https://stackoverflow.com/questions/16216868/get-back-a-string-representation-from-computedigestalgorithm-value-byte
function SHA_256 (str) {
return Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, str).reduce(function(str,chr){
chr = (chr < 0 ? chr + 256 : chr).toString(16);
return str + (chr.length==1?'0':'') + chr;
},'');
}
var api_sha256 = SHA_256(nonce + postdata)
//Decode the API secret (the private part of the API key) from base64 // need to stringyfy
var base64 = Utilities.base64Decode(secret)
var base64s = Utilities.newBlob(base64).getDataAsString()
//Calculate the HMAC of the URI path and the SHA256, using SHA512 as the HMAC hash and the decoded API secret as the HMAC key
var hamc512_uri = Utilities.computeHmacSha256Signature(path + api_sha256,base64s)
var hamc512_uris = Utilities.newBlob(hamc512_uri).getDataAsString()
//Encode the HMAC into base64
var signature = Utilities.base64Encode(hamc512_uris)
Logger.log(signature)
//An example of the algorithm using the variables shown above is as follows:
//Base64Encode(HMAC-SHA512 of ("/0/private/TradeBalance" + SHA256("1540973848000nonce=1540973848000&asset=xxbt")) using Base64Decode("FRs+gtq09rR7OFtKj9BGhyOGS3u5vtY/EdiIBO9kD8NFtRX7w7LeJDSrX6cq1D8zmQmGkWFjksuhBvKOAWJohQ==") as the HMAC key
//The result is the API-Sign value / signature.
// connect
var url = "https://api.kraken.com" + path;
var options = {
method: 'post',
headers: {
'API-Key': key,
'API-Sign': signature
},
payload: postdata
};
var response = UrlFetchApp.fetch (url, options);
json = response.getContentText ();
Logger.log(json)
}
While I cannot spot what's wrong with your code I faced the same problem as well (thinking I have everything correct but getting a EAPI:Invalid key) with different libraries.
The approach that helped me was:
Take some posted working solution, e.g. https://stackoverflow.com/a/43081507/672008 (in Java)
Check that it really works
Fix the nonce parameter to get a stable HMAC end results
Massage my code until I get then same intermediate & end results
In the end I was successful using this library: https://www.npmjs.com/package/jssha
The code:
import jssha from 'jssha';
const secret = '...';
const nonce = 1642383717038;
const message = '';
const path = '/0/private/Balance';
const data = 'nonce=' + nonce;
const dataHash = new jssha('SHA-256', 'TEXT');
dataHash.update(nonce + data + message);
let utf8Encode = new TextEncoder();
const hmacHash = new jssha('SHA-512', 'UINT8ARRAY', { hmacKey: { value: secret, format: 'B64' } });
hmacHash.update(utf8Encode.encode(path));
hmacHash.update(dataHash.getHash('UINT8ARRAY'));
console.log('hmac', hmacHash.getHash('B64'));
In the Houndify API Docs for Authentication, you have the following block of content:
An Example of Authenticating a Request
Let's assume we have the following information:
UserID: ae06fcd3-6447-4356-afaa-813aa4f2ba41
RequestID: 70aa7c25-c74f-48be-8ca8-cbf73627c05f
Timestamp: 1418068667
ClientID: KFvH6Rpy3tUimL-pCUFpPg==
ClientKey: KgMLuq-k1oCUv5bzTlKAJf_mGo0T07jTogbi6apcqLa114CCPH3rlK4c0RktY30xLEQ49MZ-C2bMyFOVQO4PyA==
Concatenate the UserID string, RequestID string, and TimeStamp string in the following format: {user_id};{request_id}{timestamp}
With the values from the example, the expected output would be in this case: ae06fcd3-6447-4356-afaa-813aa4f2ba41;70aa7c25-c74f-48be-8ca8-cbf73627c05f1418068667
Sign the message with the decoded ClientKey. The result is a 32-byte binary string (which we can’t represent visually). After base-64 encoding, however, the signature is: myWdEfHJ7AV8OP23v8pCH1PILL_gxH4uDOAXMi06akk=
The client then generates two authentication headers Hound-Request-Authentication and Hound-Client-Authentication.
The Hound-Request-Authentication header is composed by concatenating the UserID and RequestID in the following format: {user-id};{request-id}. Continuing the example above, the value for this header would be:
Hound-Request-Authentication: ae06fcd3-6447-4356-afaa-813aa4f2ba41;70aa7c25-c74f-48be-8ca8-cbf73627c05f
The Hound-Client-Authentication header is composed by concatening the ClientID, the TimeStamp string and the signature in the following format: {client-id};{timestamp};{signature}. Continuing the example above, the value for this header would be: Hound-Client-Authentication: KFvH6Rpy3tUimL-pCUFpPg==;1418068667;myWdEfHJ7AV8OP23v8pCH1PILL_gxH4uDOAXMi06akk=
For Number 3, it says "Sign the message with the decoded ClientKey". The "message" and "ClientKey" are two distinct strings.
My question(s): How do you sign one string with another string i.e. what exactly does that mean? And how would you do that in JavaScript?
var message = 'my_message';
var key = 'signing_key';
//??what next??
I'm trying to figure all this out so I can create a pre-request script in Postman to do a proper HmacSHA256 hash.
According to the documentation, if you're using one of their SDKs, it will automatically authenticate your requests:
SDKs already handle authentication for you. You just have to provide
the SDK with the Client ID and Client Key that was generated for your
client when it was created. If you are not using an SDK, use the code
example to the right to generate your own HTTP headers to authenticate
your request.
However, if you want to do it manually, I believe you need to compute the HMAC value of the string they describe in the link in your question and then send it base64 encoded as part of the Hound-Client-Authentication header in your requests. They provide an example for node.js:
var uuid = require('node-uuid');
var crypto = require('crypto');
function generateAuthHeaders (clientId, clientKey, userId, requestId) {
if (!clientId || !clientKey) {
throw new Error('Must provide a Client ID and a Client Key');
}
// Generate a unique UserId and RequestId.
userId = userId || uuid.v1();
// keep track of this requestId, you will need it for the RequestInfo Object
requestId = requestId || uuid.v1();
var requestData = userId + ';' + requestId;
// keep track of this timestamp, you will need it for the RequestInfo Object
var timestamp = Math.floor(Date.now() / 1000),
unescapeBase64Url = function (key) {
return key.replace(/-/g, '+').replace(/_/g, '/');
},
escapeBase64Url = function (key) {
return key.replace(/\+/g, '-').replace(/\//g, '_');
},
signKey = function (clientKey, message) {
var key = new Buffer(unescapeBase64Url(clientKey), 'base64');
var hash = crypto.createHmac('sha256', key).update(message).digest('base64');
return escapeBase64Url(hash);
},
encodedData = signKey(clientKey, requestData + timestamp),
headers = {
'Hound-Request-Authentication': requestData,
'Hound-Client-Authentication': clientId + ';' + timestamp + ';' + encodedData
};
return headers;
};
So basically, signing [in this specific case] simply means to create a hash of the string using a hash algorithm in addition to a key, as opposed to a keyless hash [like MD5]. For example:
var message = 'my_message';
var key = 'signing_key';
var hashed_message = hash_func(message, key);
where hash_func is a hashing algorithm like HmacSHA256 (the hashing algorithm in question).
The reason I was trying to figure this out was to test authentication for the Houndify API using Postman. Fortunately, Postman has a nice feature called pre-request scripts [complete with hashing algorithms] that helps if you need to pre-generate values that need to be sent along with your request.
After much fiddling around, I managed to create a pre-request script that properly authenticates to this API (see code below).
var unescapeBase64Url = function (key) {
return key.replace(/-/g, '+').replace(/_/g, '/');
},
escapeBase64Url = function (key) {
return key.replace(/\+/g, '-').replace(/\//g, '_');
},
guid = function() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
var client_id_str = environment["client-id"];
var client_key_str = environment["client-key"];
var user_id_str = environment["user-id"];
var request_id_str = guid();
var timestamp_str = Math.floor(Date.now() / 1000);
var client_key_dec_str = CryptoJS.enc.Base64.parse(unescapeBase64Url(client_key_str));
var message_str = user_id_str+";"+request_id_str+timestamp_str;
var signature_hash_obj = CryptoJS.HmacSHA256(message_str, client_key_dec_str);
var signature_str = signature_hash_obj.toString(CryptoJS.enc.Base64);
var hound_request_str = user_id_str+";"+request_id_str;
var hound_client_str = client_id_str+";"+timestamp_str+";"+escapeBase64Url(signature_str);
postman.setEnvironmentVariable("hound-request-authentication", hound_request_str);
postman.setEnvironmentVariable("hound-client-authentication", hound_client_str);
Note that you are going to have to create environment variables in Postman for client-id, client-key, and user-id, as well as for the header variables hound-request-authentication and hound-client-authentication to hold the final values that will be referenced when defining headers.
Hope it helps.
I understand that there exist other libraries which make my life easier to work with JWT (in node.js).
In this case, I am using "crypto-js" to learn JWT in a manual way. The following gives me the token:
var header = {
"alg": "HS256",
"typ": "JWT"
};
var wordArrayHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
var base64Header = CryptoJS.enc.Base64.stringify(wordArrayHeader);
var payload = {
"sub": "1234567890",
"name": "John Doe",
"admin": true
};
var wordArrayPayload = CryptoJS.enc.Utf8.parse(JSON.stringify(payload));
var base64Payload = CryptoJS.enc.Base64.stringify(wordArrayPayload);
var signature = CryptoJS.HmacSHA256(base64Header + "." + base64Payload , "secret");
var base64Sign = CryptoJS.enc.Base64.stringify(signature);
var token = base64Header + "." + base64Payload + "." + base64Sign;
I am unable to do the exact opposite, to verify the token. For example, the following throws me an error when decrypting the signature:
var token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
var base64Header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
var base64Payload = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
var base64Sign = "TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
var parsedSignArray = CryptoJS.enc.Base64.parse(base64Sign);
var parsedSign = parsedSignArray.toString(CryptoJS.enc.Utf8);
var decrypted = CryptoJS.HmacSHA256.decrypt(parsedSign , "secret");
console.log(decrypted);
What am I missing here? BTW, just for this example, I am using token from http://jwt.io
There is no such thing as CryptoJS.HmacSHA256.decrypt. Since HMAC, as well as hash functions in general, are one-way functions the only way to verify the "signature" would be to run the same one way function over the same string and then compare it with the one that you've got:
var signature = CryptoJS.HmacSHA256(base64Header + "." + base64Payload , "secret").toString(CryptoJS.enc.Base64);
var valid = signature == base64Sign;