I have read through the docs and every post, on Stack Overflow, I could find on creating a signature for NetSuite OAuth1.0 with TBA. From what I can see I am inputting all of the requirements and correctly creating the key however when I make the call to the server I am still getting
"Refused to set unsafe header "Cookie"
I have done the following:
I can confirm I have been unable to replicate the signature from postman (using the same parameter values) however I did read a post that, that does not necessarily indicate I am wrong since postman uses some other PM specific parameters/variables (not sure how valid that is.)
I have followed the documentation here: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_157652390285.html as well as all of the related docs.
the following post is the closest to answering the questions however NetSuite no longer supports HMAC-SHA1, but other than me changing to HMAC-SHA256 I am providing all of the same parameters.(and then some per the docs.)
similar question with answer that I believe I am matching minus some additions from NS docs: Netsuite Rest Web Services Signature
One problem I am having is that all of the docs use PHP so I am trying to match that with the javascript equivalent. but I have never worked in php so I am no sure if I am using the wrong encoding methods or not.
import axios from 'axios';
import { nanoid } from 'nanoid';
import hmacSHA256 from 'crypto-js/hmac-sha256'
import base64 from 'crypto-js/enc-base64'
function encodeRFC3986URIComponent(str: string) {
return encodeURIComponent(str)
.replace(
/[!'()*]/g,
(c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
);
}
const parameters = {
grant_type: "client_credentials",
oauth_consumer_key: consumerKey,
oauth_signature_method: "HMAC-SHA256",
oauth_timestamp: timeStamp,
oauth_token: accessToken,
oauth_nonce: nonce,
oauth_version: "1.0",
};
const signatureKey = encodeURIComponent(consumerSecret) + '&' + encodeURIComponent(tokenSecret)
console.log('signatureKey: ', signatureKey)
var baseString = httpMethod + '&' + requestURL;
for (const key in parameters) {
baseString += "&" + key + "=" + parameters[key as keyof object];
}
const encodedBaseString = encodeRFC3986URIComponent(baseString)
const signature = base64.stringify(hmacSHA256(encodedBaseString, signatureKey));
let data = JSON.stringify({
"q": "SELECT id, entityid FROM employee WHERE custentity_time_badge = '12345'"
});
let authorizationHeader = 'OAuth realm=' + OauthRealm
for (const key in parameters) {
authorizationHeader += ',' + key + "=" + parameters[key as keyof object];
}
authorizationHeader += ',oauth_signature=' + signature
authorizationHeader = JSON.stringify(authorizationHeader)
let config = {
method: 'post',
maxBodyLength: Infinity,
url: 'https://5283244-sb2.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql',
headers: {
'prefer': 'transient',
'Content-Type': 'application/json',
'Authorization': authorizationHeader,
'Cookie': 'NS_ROUTING_VERSION=LAGGING'
},
data: data
};
axios.request(config)
.then((response) => {
console.log(JSON.stringify(response.data));
})
.catch((error) => {
console.log(error);
});
Thanks to Krypton for getting me pointed in the right direction. after he helped me isolate the problem to truly being the wrong credentials, I went to the following doc and started from scratch to create a signature that matched the signature in the doc.
Doc: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_1534941088.html
After I worked out the issues that were causing the signature to be incorrect I had a working example.
and now my code is as follows
const parameters = {
oauth_consumer_key: consumerKey,
oauth_nonce: nonce,
oauth_signature_method: "HMAC-SHA256",
oauth_timestamp: timeStamp,
oauth_token: tokenKey,
oauth_version: "1.0",
};
let e_baseString = httpMethod + '&' + encodeURIComponent(requestURL) + '&'
let firstiteration = 0
for (const key in parameters) {
if (firstiteration === 0) {
e_baseString += key + "%3D" + parameters[key as keyof object];
firstiteration = 1
} else {
e_baseString += "%26" + key + "%3D" + parameters[key as keyof object];
}
}
const e_key = encodeURIComponent(consumerSecret) + '&' + encodeURIComponent(tokenSecret)
let signature = base64.stringify(hmacSHA256(e_baseString, e_key))
signature = encodeURIComponent(signature)
let authorizationHeader = 'OAuth realm="' + OauthRealm + '"'
for (const key in parameters) {
authorizationHeader += ',' + key + '="' + parameters[key as keyof object] + '"';
}
authorizationHeader += ',oauth_signature="' + signature + '"'
console.log('authorizationHeader: ', authorizationHeader)
let data = JSON.stringify({
"q": "SELECT id, entityid FROM employee WHERE custentity_time_badge = '123456'"
});
let config = {
method: 'post',
maxBodyLength: Infinity,
url: 'https://5283244-sb2.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql',
headers: {
'prefer': 'transient',
'Content-Type': 'application/json',
'Authorization': authorizationHeader,
},
data: data
};
axios.request(config)
.then((response) => {
console.log(JSON.stringify(response.data));
})
.catch((error) => {
console.log(error);
});
Once again, Thanks Krypton I am working with multiple new frameworks/libraries ect. you helping me to isolate the problem was a huge help.