Enable Token-Based Authentication (Denali)

Prepare your SuiteCommerce Advanced or Site Builder Extensions implementation to use token-based authentication with the developer tools, including the extension, theme, and SuiteCommerce Advanced tools, as described in the following steps. You need to update several files, add new files, and then also download new developer tools, so be sure to complete all of the required steps as outlined in the following procedures:

Modify the index.js File for Gulp Deployments

  1. In the SuiteCommerce Advanced source directory, open this file: .../gulp/ns-deploy/index.js

  2. Find the following line of code:

                    , doUntilGetRoles 
    
                  

    And replace it with the following lines of code:

                    , ui.selectToken
    , net.authorize 
    
                  
  3. Find the following lines of code:

                    async.apply(ui.roles, deploy),
    net.targetFolder, 
    
                  

    And replace them with the following code:

                    async.apply(net.targetFolder, deploy), 
    
                  
  4. Find the following lines of code:

                    ,   ui.email
    ,   ui.password
    ,   net.roles
    ,   ui.roles 
    
                  

    And replace them with the following code:

                    ,   ui.selectToken
    ,   net.authorize 
    
                  

Modify the tool.js File

  1. In the SuiteCommerce Advanced source directory, open this file: .../gulp/ns-deploy/suitetalk4node/src/tool.js

  2. Find the following line of code:

                    nsVersion: '2015_1' 
    
                  

    And replace it with the following code:

                    nsVersion: '2020_2' 
    
                  

Modify the getDataCenterUrls.tpl File

  1. In the SuiteCommerce Advanced source directory, open this file: .../gulp/ns-deploy/suitetalk4node/src/templates/getDataCenterUrls.tpl

  2. File the following line:

                    <nsmessages:account>{{account}}</nsmessages:account> 
    
                  

    And replace it with the following code:

                    <nsmessages:account>{{‌credentials.account}}</nsmessages:account> 
    
                  

Modify the template.js File

  1. In the SuiteCommerce Advanced source directory, open this file: .../gulp/ns-deploy/suitetalk4node/src/template.js

  2. Find the following lines of code:

                    var Handlebars = require('handlebars')
    ,   fs = require('fs') 
    
                  

    And replace them with the following code:

                    var Handlebars = require('handlebars')
    ,   OAuth1 = require('oauth1').OAuth1
    ,   fs = require('fs') 
    
                  
  3. Find the _template method:

                    ,   _template: function(file_name, params)
         {
                this._initTemplateContext(params);
                var fileName = path.join(__dirname, '/templates/', file_name);
                var template = Handlebars.compile(fs.readFileSync(fileName, {encoding: 'utf8'}).toString());
                return template(params);
       } 
    
                  

    And replace it with the following code:

                    ,   _template: function(file_name, params)
        {
            var self = this;
            var oauth1 = new OAuth1(this.credentials);
            return oauth1.soapAuthorize(this.credentials.authID).then(function(credentials) {
                self._initTemplateContext(params);
                params.credentials = params.credentials || {};
                params.credentials.vm = self.credentials.vm;
                params.credentials.molecule = self.credentials.molecule;
                params.credentials.authID = self.credentials.authID;
                params.credentials.token = credentials.token || self.credentials.token;
                params.credentials.signature = credentials.signature || self.credentials.signature;
                params.credentials.nonce = credentials.nonce || self.credentials.nonce;
                params.credentials.timestamp = credentials.timestamp || self.credentials.timestamp;
                params.credentials.account = credentials.account || self.credentials.account;
                params.credentials.consumerKey = credentials.consumerKey || self.credentials.consumerKey;
                var fileName = path.join(__dirname, '/templates/', file_name);
                var template = Handlebars.compile(fs.readFileSync(fileName, {encoding: 'utf8'}).toString());
                return template(params);
            });
        } 
    
                  

Modify the communication.js File

  1. In the SuiteCommerce Advanced source directory, open this file: .../gulp/ns-deploy/suitetalk4node/src/communications.js

  2. Find the following lines of code:

                    ,   _request: function(action, payload, cb)
         { 
    
                  

    And replace them with the following code:

                    ,   _request: function(action, payload, cb)
        {
            cb = cb || function(){}; 
    
                  
  3. Find the _request method:

                    ,   __request: function(action, payload, cb)
        {
            var self = this
            ,   deferred =  Q.defer();     
            cb = cb || function(){};
            var datacenterDomain =  self.dataCenterDomains && self.dataCenterDomains.webservices || 'https://webservices.netsuite.com';
            var req = request({
                    method: 'POST'
                ,   uri: datacenterDomain + '/services/NetSuitePort_' + self.nsVersion
                ,   headers: {
                        'User-Agent': 'Node-SOAP/0.0.1'
                    ,   'Accept': 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8'
                    ,   'Accept-Encoding': 'none'
                    ,   'Accept-Charset': 'utf-8'
                    ,   'Connection': 'close'
                    ,   'Content-Type': 'text/xml; charset=utf-8'
                    ,   'SOAPAction': '"' + action + '"'
                    ,   'Expect': '100-continue'
                    }
            }, function(err, response)
            {
                if (err)
                {
                    return cb(err);
                }
     
                self.log('Response text for action: ' + action + '\n' + response.body);
                xml2js.parseString(response.body, self._xml2jsOptions , function(err, result)
                {
                    // console.log('json response: ', JSON.stringify(result.Envelope.Body, null,2))
                    if (err)
                    {
                        deferred.reject(err);
                        return cb(err);
                    }
                    var soap_body = result.Envelope.Body[0];
                    if (soap_body && soap_body.Fault)
                    {
                        deferred.reject(new Error(soap_body.Fault[0].faultstring[0]));
                        return cb(new Error(soap_body.Fault[0].faultstring[0]));
                    }
                    deferred.resolve(soap_body);
                    cb(null, soap_body, result);
                });
            });
             
            self.log('Request text for action: ' + action+'\n'+ payload);
            // console.log(payload);
            // payload = prettyData.xmlmin(payload); //minify xml
            req.end(payload);
            return deferred.promise;
        } 
    
                  

    And replace it with the following code:

                    ,   __request: function(action, payload, cb) {
        const self = this;
     
        cb = cb || function() {};
        const datacenterDomain =
            (self.dataCenterDomains && self.dataCenterDomains.webservices) ||
            this.getDefaultWebServiceUrl();
     
        const args = require('yargs').argv;
        if (args.proxy) {
            request = request.defaults({ proxy: args.proxy });
        }
        return payload.then(function(payloadResult) {
            return new Promise(function(resolve, reject) {
                const req = request(
                    {
                        method: 'POST',
                        uri: datacenterDomain + "/services/NetSuitePort_" + self.nsVersion,
                        headers: {
                            'User-Agent': self.credentials.user_agent || 'Node-SOAP/0.0.1',
                            Accept:
                                'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8',
                            'Accept-Encoding': 'none',
                            'Accept-Charset': 'utf-8',
                            Connection: 'close',
                            'Content-Type': 'text/xml; charset=utf-8',
                            SOAPAction: '"' + action + '"'
                        }
                    },
                    function(err, response) {
                        if (err) {
                            return cb(err);
                        }
     
                        xml2js.parseString(response.body, self._xml2jsOptions, function(
                            err,
                            result
                        ) {
                            if (err) {
                                reject(err);
                                return cb(err);
                            }
                            const soap_body = result.Envelope.Body[0];
                            if (soap_body && soap_body.Fault) {
                                reject(new Error(soap_body.Fault[0].faultstring[0]));
                                return cb(new Error(soap_body.Fault[0].faultstring[0]));
                            }
                            resolve(soap_body);
     
                            cb(null, soap_body, result);
                        });
                    }
                );
     
                req.end(payloadResult);
            });
        });
    } 
    
                  
  4. Add the getDefaultWebServiceUrl method directly above the request method in the communications.js file as shown in the following example:

                                 ,   getDefaultWebServiceUrl: function()
            {
                if (this.credentials.molecule)
                {
                    return 'https://webservices.' + this.credentials.molecule + '.netsuite.com'
                }
                if(this.credentials.vm)
                {
                    return this.credentials.vm;
                }
                else
                {
                    return 'https://webservices.netsuite.com'  
                }
            }
     
        //@method __request - has the same signature as _request but it won't perform the data center domain verification.
    ,   __request: function(action, payload, cb) { 
    
                  

Modify the passport.tpl File

  1. In the SuiteCommerce Advanced source directory, open this file: ...gulp/ns-deploy/suitetalk4node/src/templates/_passport.tpl

  2. Find the following lines of code:

                    <nsmessages:passport>
            {{#if credentials.email}}<nscore:email>{{‌credentials.email}}</nscore:email>{{/if}}
            {{#if credentials.password}}<nscore:password>{{‌credentials.password}}</nscore:password>{{/if}}
            {{#if credentials.account}}<nscore:account>{{‌credentials.account}}</nscore:account>{{/if}}
            {{#if credentials.roleId}}<nscore:role internalId="{{‌credentials.roleId}}"/>{{/if}}
    </nsmessages:passport> 
    
                  

    And replace them with the following code:

                    <ns:tokenPassport actor="http://schemas.xmlsoap.org/soap/actor/next" mustUnderstand="0" 
     xmlns:ns="urn:messages_2020_1.platform.webservices.netsuite.com">   
       {{#if credentials.account}}<ns:account>{{‌credentials.account}}</ns:account>{{/if}}
       {{#if credentials.consumerKey}}<ns:consumerKey>{{‌credentials.consumerKey}}</ns:consumerKey>{{/if}}
       {{#if credentials.token}}<ns:token>{{‌credentials.token}}</ns:token>{{/if}}
       {{#if credentials.nonce}}<ns:nonce>{{‌credentials.nonce}}</ns:nonce>{{/if}}
       {{#if credentials.timestamp}}<ns:timestamp>{{‌credentials.timestamp}}</ns:timestamp>{{/if}}
       {{#if credentials.signature}}<ns:signature algorithm="HMAC_SHA256">{{‌credentials.signature}}</ns:signature>{{/if}}
    </ns:tokenPassport> 
    
                  

Modify package.json Dependencies

  1. In the top level of the SuiteCommerce Advanced source directory, open the package.json file.

  2. Add the following line to the dependencies:

                    "oauth1": "file:./ns_npm_repository/oauth1", 
    
                  

    As shown in the following example excerpt:

                    "dependencies": {
            "oauth1": "file:./ns_npm_repository/oauth1",
            "ansi-colors": "2.0.1",
            "archiver": "2.1.1",
            "async": "2.6.1", 
    
                  

Modify the fs.js File

  1. In the SuiteCommerce Advanced source directory, open this file: .../gulp/ns-deploy/fs.js

  2. Find the following lines of code:

                    ,   processBackup: function(deploy, took, cb)
        {
            gutil.log('Finished', gutil.colors.cyan('Deploy website' + (took ? ', took ' + took : '') ) ); 
    
                  

    And replace them with the following code:

                       ,   processBackup: function(deploy, cb)
         {
                 gutil.log('Finished', gutil.colors.cyan('Deploy website') ); 
    
                  
  3. Find the following line of code:

                    cb(null, deploy, context, took); 
    
                  

    And replace it with the following code:

                    cb(null, deploy, context); 
    
                  

Modify the filecabinet-util.js File

  1. In the SuiteCommerce Advanced source directory, open this file: .../gulp/ns-deploy/ns-uploader/src/filecabinet-util.js

  2. Add the getFolderNamed method directly above the addOrUplodateFile method as shown in the following example:

                    ,   getFolderNamed: function(parentFolderId, fileName, doGet)
        {
            return this.getFileNamed(parentFolderId, fileName, doGet, true);
        }
     
    ,   addOrUplodateFile: function(parentFolderId, fileName, fileContents, fileType) 
    
                  

Create the ns_npm_repository/oauth1 Directory

  1. In the top level of the SuiteCommerce Advanced source directory, create a new directory named ns_npm_repository.

  2. Copy the oauth1 folder from the TBApatch-denali.zip file to the new ns_npm_repository directory you created in the preceding step.

Replace Gulp Files

Replace the following files in the SuiteCommerce Advanced source directory with the modified versions of the same files available in the .zip file for this patch: TBApatch-denali.zip

  • .../gulp/ns-deploy/net.js

  • .../gulp/ns-deploy/ui.js

Run NPM Command for oauth1

After updating all files as required, adding new files from the .zip file for the patch, and downloading and setting up the theme and extension developer tools, you must run the following command to ensure that token-based authentication functions properly.

Run the following command at the top level of the SuiteCommerce Advanced source directory:

npm i oauth1

When this command completes, continue with additional updates for token-based authentication. For detailed instructions, see Token-Based Authentication Updates for Developer Tools.

Related Topics

General Notices