ServiceNow to NetSuite Integration via Oauth 2.0 alg PS256

elvadeocampo
Giga Contributor

We needed to call a NetSuite API from ServiceNow, authenticating via Oauth 2.0 Client Credentials. NetSuite requires JWT for this. Algorithm RS256 is supported by ServiceNow out of the box. However, NetSuite deprecated RS256 just this year. I had to find another/custom way.

After a ton of searching and reading and watching videos from the ServiceNow community, here's how I was able to create a JWT that NetSuite was happy with. 

  1. Generate Certificate and JKS file. Sample openssl and keytool commands are taken from post Running a GitHub bot from SN.
  2. Create "x509 Certificate" record in ServiceNow, type Java Key Store
  3. Script below:
  • Create the JWT header and payload. Base64 encode using GlideStringUtil.base64Encode() ServiceNow API
    • functions to base64 encode and clean up chars
function encodeBase64(str) {
    var base64string = str;
    
	base64string = GlideStringUtil.base64Encode(str);
	base64string = cleanChars(base64string);

    return base64string;
}

function cleanChars(strToClean) {
    strToClean = (strToClean + "").replace(/=/g, "");
    strToClean = (strToClean + "").replace(/\+/g, "-");
    strToClean = (strToClean + "").replace(/\//g, "_");
	return strToClean;
}
  • create the jwt header
//CREATE JWT HEADER
var headerJSON = {
    typ: "JWT",
    alg: "PS256", 
    kid: "CERTIFICATE ID IN NETSUITE" //fixed value; Certificate id in NS
};
var header = JSON.stringify(headerJSON);
var jwtHeader = encodeBase64(header);
  • create the jwt payload
//CREATE JWT PAYLOAD
var payloadJSON = {
    iss: 'consumer key in netsuite',
    scope: ['restlets', 'rest_webservices'], // depends on your NetSuite integration record
    iat: (new Date() / 1000),
    exp: (new Date() / 1000) + 3600,
    aud: 'URL of Netsuite token endpoint'
};
var payload = JSON.stringify(payloadJSON);
var jwtPayload = encodeBase64(payload);
  • Use ServiceNow's GlideCertificateEncryption() API to sign header and payload. The API returns signed data in base64 already. Need only to cleanup invalid characters
// Initialize GlideCertificateEncryption parameters
var CERT_RECORD_SYS_ID = 'Sys id of you x509 certificate';  // type should be Java Key Store
var KEYSTORE_ALIAS = '1'; // fixed value; so value is always "1", store only 1 certificate in the JKS
var KEYSTORE_PWD = 'java keystore password';
var SIGNING_ALGO = 'SHA256withRSAandMGF1'; // fixed value MUST use this for PS256
var STRING_TO_SIGN = jwtHeader + '.' + jwtPayload;

var ce = new GlideCertificateEncryption(); 
var signed = ce.sign(CERT_RECORD_SYS_ID, KEYSTORE_ALIAS, KEYSTORE_PWD, SIGNING_ALGO, STRING_TO_SIGN);
var signedBase64 = cleanChars(signed);
  • Finally, assemble the final JWT string (header payload signedpayload)
var jwt = jwtHeader + '.' + jwtPayload + '.' + signedBase64;
gs.info("jwt: \n" + jwt);

One caveat: I used the "SHA256withRSAandMGF1" (the signing algorithm for PS256) with GlideCertificateEncryption, which is functional but not officially documented. Fingers crossed it stays supported in future releases.

 

Hopefully this helps someone else facing the same challenge.

 

0 REPLIES 0