Possible i “up vote” the feature? we are also looking forward for NetSuite’s auth node. But we likely can’t afford the self-host version.
Installing of community node required self-host as per my understanding
update 17 Jul 2024: i managed to create a node program to auth with NetSuite, next step is to build it via javascript, so i dont need to use the hosted n8n. Finger cross
const request = require('request')
const crypto = require('crypto')
// NetSuite specific parameters
const ACCOUNT_ID = 'x'
const COMPANY_URL = 'x.suitetalk.api.netsuite.com'
const REST_SERVICES = '/services/rest'
// OAuth credentials
const CONSUMER_KEY = 'x'
const CONSUMER_SECRET = 'x' // Replace with actual secret
const TOKEN_KEY = 'x'
const TOKEN_SECRET = 'x' // Replace with actual secret
/* */
const request_data = {
url: `https://${COMPANY_URL}${REST_SERVICES}/query/v1/suiteql`,
method: 'POST',
}
// const request_data = {
// url: `https://${COMPANY_URL}${REST_SERVICES}/record/v1/journalentry`,
// method: 'GET',
// data: { },
// }
function generateNonce(length = 32) {
return crypto.randomBytes(length).toString('hex')
}
function generateAuthHeader() {
const timestamp = Math.floor(Date.now() / 1000).toString()
const nonce = generateNonce()
const data = {
oauth_consumer_key: CONSUMER_KEY,
oauth_token: TOKEN_KEY,
oauth_signature_method: 'HMAC-SHA256',
oauth_timestamp: timestamp,
oauth_nonce: nonce,
oauth_version: '1.0'
}
const encodedData = Object.keys(data)
.sort()
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
.join('&')
const baseString = `${request_data.method}&${encodeURIComponent(request_data.url)}&${encodeURIComponent(encodedData)}`
const signingKey = `${encodeURIComponent(CONSUMER_SECRET)}&${encodeURIComponent(TOKEN_SECRET)}`
const signature = crypto.createHmac('sha256', signingKey)
.update(baseString)
.digest('base64')
return `OAuth realm="${ACCOUNT_ID}",oauth_consumer_key="${CONSUMER_KEY}",oauth_token="${TOKEN_KEY}",oauth_signature_method="HMAC-SHA256",oauth_timestamp="${timestamp}",oauth_nonce="${nonce}",oauth_version="1.0",oauth_signature="${encodeURIComponent(signature)}"`
}
console.log('Starting authentication process...');
const authHeader = generateAuthHeader()
console.log('Generated Auth Header:', authHeader)
request(
{
url: request_data.url,
method: request_data.method,
headers: {
'Authorization': authHeader,
'Content-Type': 'application/json',
'Prefer': 'transient'
},
body: JSON.stringify({ q: 'SELECT * FROM currency' })
// body: JSON.stringify({}) // if using suiteql, comment this and enable line above
},
function(error, response, body) {
if (error) {
console.error('Error occurred:', error);
return;
}
console.log('Response Status Code:', response.statusCode);
console.log('Response Headers:', JSON.stringify(response.headers, null, 2));
if (response.statusCode === 200) {
console.log('Request successful!');
try {
const data = JSON.parse(body);
console.log('Response data:', JSON.stringify(data, null, 2));
} catch (e) {
console.error('Error parsing response:', e);
console.log('Raw response body:', body);
}
} else {
console.log('Request failed.');
console.log('Response Body:', body);
try {
const error = JSON.parse(body);
if (error['o:errorDetails'] && error['o:errorDetails'].length > 0) {
console.log('Error message:', error['o:errorDetails'][0].detail);
console.log('Error code:', error['o:errorDetails'][0]['o:errorCode']);
} else {
console.log('Unexpected error format:', error);
}
} catch (e) {
console.error('Error parsing error response:', e);
console.log('Raw error body:', body);
}
}
}
)