04 Aug 2023 03:46 PM - edited 29 Apr 2026 01:43 PM
You can find more information on how to create a signed AWS API request, using AWS Signature Version 4, here.
🔐 This script follows the AWS SigV4 signing process as documented by AWS.
/*
This code generates a signed Authorization header for an HTTP request for AWS
See the following for how to sign a request for AWS Signature Version 4:
https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
*/
// CryptoJS rollup code for HMACSha256 and Sha256
var CryptoJS=CryptoJS||function(h,s){var f={},g=f.lib={},q=function(){},m=g.Base={extend:function(a){q.prototype=this;var c=new q;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},r=g.WordArray=m.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=s?c:4*a.length},toString:function(a){return(a||k).stringify(this)},concat:function(a){var c=this.words,d=a.words,b=this.sigBytes;a=a.sigBytes;this.clamp();if(b%4)for(var e=0;e<a;e++)c[b+e>>>2]|=(d[e>>>2]>>>24-8*(e%4)&255)<<24-8*((b+e)%4);else if(65535<d.length)for(e=0;e<a;e+=4)c[b+e>>>2]=d[e>>>2];else c.push.apply(c,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<32-8*(c%4);a.length=h.ceil(c/4)},clone:function(){var a=m.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],d=0;d<a;d+=4)c.push(4294967296*h.random()|0);return new r.init(c,a)}}),l=f.enc={},k=l.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++){var e=c[b>>>2]>>>24-8*(b%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b+=2)d[b>>>3]|=parseInt(a.substr(b,2),16)<<24-4*(b%8);return new r.init(d,c/2)}},n=l.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++)d.push(String.fromCharCode(c[b>>>2]>>>24-8*(b%4)&255));return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b++)d[b>>>2]|=(a.charCodeAt(b)&255)<<24-8*(b%4);return new r.init(d,c)}},j=l.Utf8={stringify:function(a){try{return decodeURIComponent(escape(n.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return n.parse(unescape(encodeURIComponent(a)))}},u=g.BufferedBlockAlgorithm=m.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=j.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,d=c.words,b=c.sigBytes,e=this.blockSize,f=b/(4*e),f=a?h.ceil(f):h.max((f|0)-this._minBufferSize,0);a=f*e;b=h.min(4*a,b);if(a){for(var g=0;g<a;g+=e)this._doProcessBlock(d,g);g=d.splice(0,a);c.sigBytes-=b}return new r.init(g,b)},clone:function(){var a=m.clone.call(this);a._data=this._data.clone();return a},_minBufferSize:0});g.Hasher=u.extend({cfg:m.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){u.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(c,d){return(new a.init(d)).finalize(c)}},_createHmacHelper:function(a){return function(c,d){return(new t.HMAC.init(a,d)).finalize(c)}}});var t=f.algo={};return f}(Math);(function(h){for(var s=CryptoJS,f=s.lib,g=f.WordArray,q=f.Hasher,f=s.algo,m=[],r=[],l=function(a){return 4294967296*(a-(a|0))|0},k=2,n=0;64>n;){var j;a:{j=k;for(var u=h.sqrt(j),t=2;t<=u;t++)if(!(j%t)){j=!1;break a}j=!0}j&&(8>n&&(m[n]=l(h.pow(k,0.5))),r[n]=l(h.pow(k,1/3)),n++);k++}var a=[],f=f.SHA256=q.extend({_doReset:function(){this._hash=new g.init(m.slice(0))},_doProcessBlock:function(c,d){for(var b=this._hash.words,e=b[0],f=b[1],g=b[2],j=b[3],h=b[4],m=b[5],n=b[6],q=b[7],p=0;64>p;p++){if(16>p)a[p]=c[d+p]|0;else{var k=a[p-15],l=a[p-2];a[p]=((k<<25|k>>>7)^(k<<14|k>>>18)^k>>>3)+a[p-7]+((l<<15|l>>>17)^(l<<13|l>>>19)^l>>>10)+a[p-16]}k=q+((h<<26|h>>>6)^(h<<21|h>>>11)^(h<<7|h>>>25))+(h&m^~h&n)+r[p]+a[p];l=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&f^e&g^f&g);q=n;n=m;m=h;h=j+k|0;j=g;g=f;f=e;e=k+l|0}b[0]=b[0]+e|0;b[1]=b[1]+f|0;b[2]=b[2]+g|0;b[3]=b[3]+j|0;b[4]=b[4]+h|0;b[5]=b[5]+m|0;b[6]=b[6]+n|0;b[7]=b[7]+q|0},_doFinalize:function(){var a=this._data,d=a.words,b=8*this._nDataBytes,e=8*a.sigBytes;d[e>>>5]|=128<<24-e%32;d[(e+64>>>9<<4)+14]=h.floor(b/4294967296);d[(e+64>>>9<<4)+15]=b;a.sigBytes=4*d.length;this._process();return this._hash},clone:function(){var a=q.clone.call(this);a._hash=this._hash.clone();return a}});s.SHA256=q._createHelper(f);s.HmacSHA256=q._createHmacHelper(f)})(Math);(function(){var h=CryptoJS,s=h.enc.Utf8;h.algo.HMAC=h.lib.Base.extend({init:function(f,g){f=this._hasher=new f.init;"string"==typeof g&&(g=s.parse(g));var h=f.blockSize,m=4*h;g.sigBytes>m&&(g=f.finalize(g));g.clamp();for(var r=this._oKey=g.clone(),l=this._iKey=g.clone(),k=r.words,n=l.words,j=0;j<h;j++)k[j]^=1549556828,n[j]^=909522486;r.sigBytes=l.sigBytes=m;this.reset()},reset:function(){var f=this._hasher;f.reset();f.update(this._iKey)},update:function(f){this._hasher.update(f);return this},finalize:function(f){var g=this._hasher;f=g.finalize(f);g.reset();return g.finalize(this._oKey.clone().concat(f))}})})();
/*
Build a signature key that is used to sign data
https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
*/
function getSignatureKey(key, dateStamp, regionName, serviceName) {
var kDate = CryptoJS.HmacSHA256(dateStamp, "AWS4" + key);
var kRegion = CryptoJS.HmacSHA256(regionName, kDate);
var kService = CryptoJS.HmacSHA256(serviceName, kRegion);
var kSigning = CryptoJS.HmacSHA256("aws4_request", kService);
return kSigning;
}
AccessKey = api.getValue("AccessKey");
SecretKey = api.getValue("SecretKey");
awsService = "execute-api";
awsRegion = api.getValue("IdentityId").split(':')[0];
now = new Date();
dateStamp = now.getUTCFullYear() + (now.getUTCMonth() < 9 ? '0' : '') + (now.getUTCMonth() + 1);
dateStamp += (now.getUTCDate() < 10 ? '0' : '') + now.getUTCDate();
signKey = getSignatureKey(SecretKey, dateStamp, awsRegion, awsService);
api.info('Signing key: ' + signKey);
/*
All the headers that need to be signed (non-default headers) and in
alphabetical order by name. I manually sorted the header order, but
this code should have a function to sort them by name in lowercase.
*/
host = '<some hostname: e.g. - www.d5.google.com>';
amzDate = dateStamp + 'T' + now.toUTCString().split(/ /)[4].replace(/\:/g, '') + 'Z';
SessionToken = api.getValue("SessionToken");
// this section must list all the headers that will be added to the request
headers = [{
"clientrequestid": "P123456789"
}, {
"content-type": "application/json"
}, {
"deviceid": "5555555"
}, {
"Host": host
}, {
"X-Amz-Date": amzDate
}, {
"X-Amz-Security-Token": SessionToken
}, {
"x-api-key": "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd123"
}, {
"x-clientapp-version": "1.2"
}, {
"x-device-id": "89406"
}, {
"x-originator-type": "app"
}
];
/*
Building the canonical request and adding the headers to the HTTP request
https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
*/
// HTTP Request parameters
method = "GET";
path = '/v1/accounts/vehicles';
queryStr = '';
payload = '';
payloadHash = CryptoJS.SHA256(payload).toString();
signedHeads = "";
canonReq = method + "\
" + path + "\
" + queryStr + "\
";
for (i = 0; i < headers.length; i++) {
name = Object.keys(headers[i])[0];
value = headers[i][name];
signedHeads += name.toLowerCase() + ";";
canonReq += name.toLowerCase() + ':' + value + '\
';
request.addHeader(name, value);
}
signedHeads = signedHeads.substr(0, signedHeads.length - 1); // remove last semi-colon
canonReq += "\
" + signedHeads + "\
" + payloadHash;
// Hash of the canonical request
canonHash = CryptoJS.SHA256(canonReq).toString();
api.info('Hash of Canonical request: ' + canonHash);
/*
Building the string to sign
https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
*/
signStr = "AWS4-HMAC-SHA256\
" + amzDate + "\
" + dateStamp + "/";
signStr += awsRegion + "/" + awsService + "/aws4_request\
" + canonHash;
api.info('String to sign: ' + signStr);
/*
Signing the string
https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
*/
sig = CryptoJS.HmacSHA256(signStr, signKey).toString();
authString = 'AWS4-HMAC-SHA256 Credential=' + AccessKey + '/' + dateStamp + '/' + awsRegion + '/' + awsService + '/aws4_request, SignedHeaders=' + signedHeads + ', Signature=' + sig;
api.info('authString: ' + authString);
request.addHeader("Authorization", authString);
If none of the previous steps resolved the issue, you can
📖 Synthetic Troubleshooting Map
📖 pre‑ and post‑execution scripts for HTTP Monitors
Hi,
I have just tried ant returns a 403:
"healthStatusCode": 6,
"healthStatus": "INVALID_CODE",
"responseBody": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details"I have just tried it using Postman and no problem. AWS keys are correct.
Best regards