使用 SuiteScript 2.x 为 DocuSign API 集成创建 JWT
Creating JWT Using SuiteScript 2.x for DocuSign API Integration
我正在更新 DocuSign 的 NetSuite 集成,以将所有脚本转换为 SuiteScript 2.0 并更新身份验证以使用 JWT 授权方法,因为目前的方法看起来将在几周内被新应用程序弃用,并完全在明年的某个时候。不过,我确实有几个问题无法回答。
首先,在为 body 设置 IAT 和 EXP 值时,我是否根据当前服务器时间获取此值(这取决于帐户数据中心恰好所在的时区),还是应该以获取 UTC 时间为基础?在这件事上,文档对我来说似乎不够清楚。
此外,我不清楚如何着手创建签名。除了上述问题之外,检索和准备必要的数据不是问题。但是,与我在创建签名时看到的示例相比,根据我在 2.0 模块中看到的可用内容安排要编码的数据似乎不太一致。例如,这是我所看到的近似值:
var header = { typ : "JWT" , alg : "RS256" };
var body = { iss : "abc123" , sub : "def456" , iat : 123456789 , exp : 123456789 + (60 * 60) , scope : "signature" };
var encHeader = base64UrlEncode(JSON.stringify(header));
var encBody = base64UrlEncode(JSON.stringify(body));
// the key pairs are stored elsewhere, and the functions represent a way to retrieve the key contents
var publickKey = retrievePublicKey();
var privateKey = retrievePrivateKey();
var signature = RS256Encode(
encHeader + "." + encBody ,
publicKey ,
privateKey
);
这些示例显示了不同的加密函数,它们都以与上述相同的方式接收三个参数。然而,当查看本机 SuiteScript 2.0 模块中可用的内容时,我没有看到任何可比性。我看到加密模块(它似乎被拉入其他模块)确实有能力执行所需的 RSA SHA256 编码,但不太确定如何确保所有部分都正确地组合在一起。
我在 https://jwt.io/ 查看了用于创建 JWT 的 JavaScript 库,但我没有尝试将节点模块合并到 SuiteScript 项目中的经验,如果可能的话。
那么,有没有一种方法可以在 SuiteScript 中本地构建 JWT,或者我是否必须找到一种方法才能在脚本中引用节点模块?
-- 编辑--
好的,看来我可以使用“异步模块定义”(AMD) 通过创建 JSON 配置文件并将以下内容添加到脚本文件的 JSDoc [=53] 来将模块导入脚本=]:
*@NAmdConfig /path/to/myModule.json
我想因为我需要它是一个相对路径,因为这个项目将分发给其他帐户,如果 JSON 配置文件在同一目录中,这样的事情应该有效:
*@NAmdConfig ./nodeModules.json
但我正忙于确定如何设置 JSON 配置。我似乎无法找到任何真正有助于确定如何正确构建它的东西。最大的问题是确定模块是 AMD 还是 non-AMD,如果 non-AMD 是否尝试导入 CJS 部分或 ESM 部分下的脚本。
对于任何其他参考,我使用 NPM 安装 jose 模块,因为它与 JavaScript/Node 兼容并且具有我需要的加密方法。
npm install jose
现在,它在源项目中的路径如下所示:
SuiteScripts/Project_Name/lib/node_modules/jose
将引用该模块的脚本文件位于此路径下:
SuiteScripts/Project_Name/lib
/**
*@NApiVersion 2.x
*/
define(['N/encode', 'N/crypto/certificate'], function(encode, cert){
function signIt(payload, ttl){
if(typeof payload.exp == 'undefined'){
var secondsSinceEpoch = Math.round(Date.now() / 1000);
var expAt = secondsSinceEpoch + (ttl || 60);
payload["exp"] = expAt;
payload["iat"] = secondsSinceEpoch;
}
log.debug({
title:'payload',
details: JSON.stringify(payload)});
var header = encode.convert({
string: JSON.stringify({
type:'JWT',
alg:'RS256'
}),
inputEncoding: encode.Encoding.UTF_8,
outputEncoding: encode.Encoding.BASE_64_URL_SAFE
}).replace(/=+$/, '');
var body = encode.convert({
string: JSON.stringify(payload),
inputEncoding: encode.Encoding.UTF_8,
outputEncoding: encode.Encoding.BASE_64_URL_SAFE}).replace(/=+$/, '');
var signer = cert.createSigner({
certId:'custcertificate_sample', //from Setup -> Company -> Certificates
algorithm: cert.HashAlg.SHA256
});
signer.update(header +'.'+ body);
var sig = signer.sign({
outputEncoding:encode.Encoding.BASE_64_URL_SAFE
}).replace(/=+$/, '');
return [header, body, sig].join('.');
}
return {
signIt: signIt
}
});
上传的密钥生成如下:
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -out public.pem -pubout
openssl req -key private.pem -new -x509 -days 3650 -subj "/C=CA/ST=Courtenay/O=Rule of Tech/OU=Information unit/CN=jwt.kotn.com" -out cert.pem
然后我只是使用文本编辑器连接来自 cert.pem 和 private.pem 的证书和私钥:
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
我正在更新 DocuSign 的 NetSuite 集成,以将所有脚本转换为 SuiteScript 2.0 并更新身份验证以使用 JWT 授权方法,因为目前的方法看起来将在几周内被新应用程序弃用,并完全在明年的某个时候。不过,我确实有几个问题无法回答。
首先,在为 body 设置 IAT 和 EXP 值时,我是否根据当前服务器时间获取此值(这取决于帐户数据中心恰好所在的时区),还是应该以获取 UTC 时间为基础?在这件事上,文档对我来说似乎不够清楚。
此外,我不清楚如何着手创建签名。除了上述问题之外,检索和准备必要的数据不是问题。但是,与我在创建签名时看到的示例相比,根据我在 2.0 模块中看到的可用内容安排要编码的数据似乎不太一致。例如,这是我所看到的近似值:
var header = { typ : "JWT" , alg : "RS256" };
var body = { iss : "abc123" , sub : "def456" , iat : 123456789 , exp : 123456789 + (60 * 60) , scope : "signature" };
var encHeader = base64UrlEncode(JSON.stringify(header));
var encBody = base64UrlEncode(JSON.stringify(body));
// the key pairs are stored elsewhere, and the functions represent a way to retrieve the key contents
var publickKey = retrievePublicKey();
var privateKey = retrievePrivateKey();
var signature = RS256Encode(
encHeader + "." + encBody ,
publicKey ,
privateKey
);
这些示例显示了不同的加密函数,它们都以与上述相同的方式接收三个参数。然而,当查看本机 SuiteScript 2.0 模块中可用的内容时,我没有看到任何可比性。我看到加密模块(它似乎被拉入其他模块)确实有能力执行所需的 RSA SHA256 编码,但不太确定如何确保所有部分都正确地组合在一起。
我在 https://jwt.io/ 查看了用于创建 JWT 的 JavaScript 库,但我没有尝试将节点模块合并到 SuiteScript 项目中的经验,如果可能的话。
那么,有没有一种方法可以在 SuiteScript 中本地构建 JWT,或者我是否必须找到一种方法才能在脚本中引用节点模块?
-- 编辑--
好的,看来我可以使用“异步模块定义”(AMD) 通过创建 JSON 配置文件并将以下内容添加到脚本文件的 JSDoc [=53] 来将模块导入脚本=]:
*@NAmdConfig /path/to/myModule.json
我想因为我需要它是一个相对路径,因为这个项目将分发给其他帐户,如果 JSON 配置文件在同一目录中,这样的事情应该有效:
*@NAmdConfig ./nodeModules.json
但我正忙于确定如何设置 JSON 配置。我似乎无法找到任何真正有助于确定如何正确构建它的东西。最大的问题是确定模块是 AMD 还是 non-AMD,如果 non-AMD 是否尝试导入 CJS 部分或 ESM 部分下的脚本。
对于任何其他参考,我使用 NPM 安装 jose 模块,因为它与 JavaScript/Node 兼容并且具有我需要的加密方法。
npm install jose
现在,它在源项目中的路径如下所示:
SuiteScripts/Project_Name/lib/node_modules/jose
将引用该模块的脚本文件位于此路径下:
SuiteScripts/Project_Name/lib
/**
*@NApiVersion 2.x
*/
define(['N/encode', 'N/crypto/certificate'], function(encode, cert){
function signIt(payload, ttl){
if(typeof payload.exp == 'undefined'){
var secondsSinceEpoch = Math.round(Date.now() / 1000);
var expAt = secondsSinceEpoch + (ttl || 60);
payload["exp"] = expAt;
payload["iat"] = secondsSinceEpoch;
}
log.debug({
title:'payload',
details: JSON.stringify(payload)});
var header = encode.convert({
string: JSON.stringify({
type:'JWT',
alg:'RS256'
}),
inputEncoding: encode.Encoding.UTF_8,
outputEncoding: encode.Encoding.BASE_64_URL_SAFE
}).replace(/=+$/, '');
var body = encode.convert({
string: JSON.stringify(payload),
inputEncoding: encode.Encoding.UTF_8,
outputEncoding: encode.Encoding.BASE_64_URL_SAFE}).replace(/=+$/, '');
var signer = cert.createSigner({
certId:'custcertificate_sample', //from Setup -> Company -> Certificates
algorithm: cert.HashAlg.SHA256
});
signer.update(header +'.'+ body);
var sig = signer.sign({
outputEncoding:encode.Encoding.BASE_64_URL_SAFE
}).replace(/=+$/, '');
return [header, body, sig].join('.');
}
return {
signIt: signIt
}
});
上传的密钥生成如下:
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -out public.pem -pubout
openssl req -key private.pem -new -x509 -days 3650 -subj "/C=CA/ST=Courtenay/O=Rule of Tech/OU=Information unit/CN=jwt.kotn.com" -out cert.pem
然后我只是使用文本编辑器连接来自 cert.pem 和 private.pem 的证书和私钥:
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----