Constantly getting Invalid Signature
when trying to create a TBA access token.
The function to generate the OAuth1.0a signature is as follows:
const restletSignature = (options) => {
const HMAC_SHA256 = (key, text, output) => {
if ( !output) output = cryptoJS.enc.Base64;
return cryptoJS.HmacSHA256(text, key).toString(output);
};
const companyInfo = config.load({
type: config.Type.COMPANY_INFORMATION,
});
const makeNonce = () => {
var result = "", characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var charactersLength = characters.length;
for (var i = 0; i < this.nonce_length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
};
try {
log.debug('options', JSON.stringify(options));
if ( !options) {
options = {};
}
if ( !options.consumer) {
throw error.create({
name: 'MISSING_PARAMTER',
message: 'consumer option is required',
notifyOff: true,
});
}
if ( !options.token) {
throw error.create({
name: 'MISSING_PARAMTER',
message: 'token option is required',
notifyOff: true,
});
}
if ( !options.restletUrl) {
throw error.create({
name: 'MISSING_PARAMTER',
message: 'restletUrl option is required',
notifyOff: true,
});
}
if (typeof options.last_ampersand === 'undefined') {
this.last_ampersand = true;
}
else {
this.last_ampersand = options.last_ampersand;
}
this.httpMethod = options.httpMethod || "POST";
this.consumer = options.consumer;
this.token = options.token;
this.nonce_length = options.nonce_length || 32;
this.signature_method = options.signature_method || "HMAC-SHA256";
this.version = options.version || '1.0';
this.parameter_separator = options.parameter_separator || ', ';
this.realm = companyInfo.getValue({fieldId: "companyid"});
this.urls = {
system: "https://" + url.resolveDomain({hostType: url.HostType.APPLICATION}),
restlet: "https://" + url.resolveDomain({hostType: url.HostType.RESTLET}),
suitetalk: "https://" + url.resolveDomain({hostType: url.HostType.SUITETALK}),
forms: "https://" + url.resolveDomain({hostType: url.HostType.FORM}),
};
this.restletFullUrl = (options.restletUrl.indexOf("https://") == -1 ? urls.system : "") + options.restletUrl;
this.restletUrl = this.restletFullUrl.indexOf("?") > -1 ? this.restletFullUrl.split("?")[0] : "";
this.restletScript = this.restletFullUrl.match(/(?<=script\=)(.*)(?=\&deploy)/);
this.restletScript = this.restletScript.length ? this.restletScript[0] : null;
this.restletDeploy = this.restletFullUrl.match(/(?<=deploy\=)(.*)(?=\&)/);
this.restletDeploy = this.restletDeploy.length ? this.restletDeploy[0] : null;
this.encodedRestletUrl = encodeURIComponent(this.restletUrl);
this.parameters = {
deploy: this.restletDeploy,
oauth_consumer_key: this.consumer.key,
oauth_nonce: makeNonce(),
oauth_signature_method: this.signature_method,
oauth_timestamp: Math.round(+new Date() / 1000),
oauth_token: this.token.key,
oauth_version: "1.0",
script: this.restletScript,
};
this.encodedParameterString = '&deploy=' + encodeURIComponent(this.parameters.deploy);
this.encodedParameterString += '&oauth_consumer_key=' + encodeURIComponent(this.parameters.oauth_consumer_key);
this.encodedParameterString += '&oauth_nonce=' + encodeURIComponent(this.parameters.oauth_nonce);
this.encodedParameterString += '&oauth_signature_method=' + encodeURIComponent(this.parameters.oauth_signature_method);
this.encodedParameterString += '&oauth_timestamp=' + encodeURIComponent(this.parameters.oauth_timestamp);
this.encodedParameterString += '&oauth_token=' + encodeURIComponent(this.parameters.oauth_token);
this.encodedParameterString += '&oauth_version=' + encodeURIComponent(this.parameters.oauth_version);
this.encodedParameterString += '&script=' + encodeURIComponent(this.parameters.script);
this.encodedParameterString = encodeURIComponent(this.encodedParameterString);
this.baseString = this.httpMethod + "&";
this.baseString += this.encodedRestletUrl + "&";
this.baseString += this.encodedParameterString;
this.signatureKey = encodeURIComponent(this.consumer.secret) + "&" + encodeURIComponent(this.consumer.secret);
this.signature = encodeURIComponent(HMAC_SHA256(this.signatureKey,this.baseString, cryptoJS.enc.Base64 ) );
this.Authorization = "";
this.Authorization += 'OAuth oauth_signature="'+this.signature + '"'+this.parameter_separator;
this.Authorization += 'oauth_version="'+this.parameters.oauth_version + '"'+this.parameter_separator;
this.Authorization += 'oauth_nonce="'+this.parameters.oauth_nonce + '"'+this.parameter_separator;
this.Authorization += 'oauth_signature_method="'+this.parameters.oauth_signature_method + '"'+this.parameter_separator;
this.Authorization += 'oauth_consumer_key="'+this.parameters.oauth_consumer_key + '"'+this.parameter_separator;
this.Authorization += 'oauth_token="'+this.parameters.oauth_token + '"'+this.parameter_separator;
this.Authorization += 'oauth_timestamp="'+this.parameters.oauth_timestamp + '"'+this.parameter_separator;
this.Authorization += 'realm="'+this.realm + '"';
} catch (e) {
this.error = {
name: e.name,
message: e.message,
stack: e.stack,
};
} finally {
return this;
}
};
The Integration record has only "Token Based Authentication" ticked.
Consumer Key/Secret and Token ID/Secret are current, and I've tried setting them multiple times.
It's all running on Server Time (PST) so I don't think Timestamp zone is an issue, but I did try adding +36000 ms (for AEST) but no change.
Logging generates this data:
{
"auth": {
"last_ampersand": true,
"httpMethod": "POST",
"consumer": {
"key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"token": {
"key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"nonce_length": 32,
"signature_method": "HMAC-SHA256",
"version": "1.0",
"parameter_separator": ", ",
"realm": "XXXXXX",
"urls": {
"system": "https://XXXXXX.app.netsuite.com",
"restlet": "https://XXXXXX.restlets.api.netsuite.com",
"suitetalk": "https://XXXXXX.suitetalk.api.netsuite.com",
"forms": "https://XXXXXX.extforms.netsuite.com"
},
"restletFullUrl": "https://XXXXXX.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=576&deploy=1&compid=XXXXXX",
"restletUrl": "https://XXXXXX.restlets.api.netsuite.com/app/site/hosting/restlet.nl",
"restletScript": "576",
"restletDeploy": "1",
"encodedRestletUrl": "https%3A%2F%9999999.restlets.api.netsuite.com%2Fapp%2Fsite%2Fhosting%2Frestlet.nl",
"parameters": {
"deploy": "1",
"oauth_consumer_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"oauth_nonce": "58RInizRvCTdBGuXtugMRPhciQ0OC1xo",
"oauth_signature_method": "HMAC-SHA256",
"oauth_timestamp": 1639901494,
"oauth_token": "b49f1560e07771f8aad11418feae49be6162cf6fbd5d98bff0ae6aac70d4a30f",
"oauth_version": "1.0",
"script": "576"
},
"encodedParameterString": "%26deploy%3D1%26oauth_consumer_key%3XXXXXXXXXXXXXXXXXXXXXXXXXXXXX%26oauth_nonce%3D58RInizRvCTdBGuXtugMRPhciQ0OC1xo%26oauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3D1639901494%26oauth_token%3Db49f1560e07771f8aad11418feae49be6162cf6fbd5d98bff0ae6aac70d4a30f%26oauth_version%3D1.0%26script%3D576",
"baseString": "POST&https%3A%2F%2F9999999.restlets.api.netsuite.com%2Fapp%2Fsite%2Fhosting%2Frestlet.nl&%26deploy%3D1%26oauth_consumer_key%3DXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%26oauth_nonce%3D58RInizRvCTdBGuXtugMRPhciQ0OC1xo%26oauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3D1639901494%26oauth_token%3Db49f1560e07771f8aad11418feae49be6162cf6fbd5d98bff0ae6aac70d4a30f%26oauth_version%3D1.0%26script%3D576",
"signatureKey": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX&XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"signature": "U5iNYAo01jMm3WLdAHUH6R8M7tzooePZ3S0Jc5KQexQ%3D",
"Authorization": "OAuth oauth_signature=\"U5iNYAo01jMm3WLdAHUH6R8M7tzooePZ3S0Jc5KQexQ%3D\", oauth_version=\"1.0\", oauth_nonce=\"58RInizRvCTdBGuXtugMRPhciQ0OC1xo\", oauth_signature_method=\"HMAC-SHA256\", oauth_consumer_key=\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX\", oauth_token=\"b49f1560e07771f8aad11418feae49be6162cf6fbd5d98bff0ae6aac70d4a30f\", oauth_timestamp=\"1639901494\", realm=\"9999999\""
}
}