ANS-0958 · SUITESCRIPT DEVELOPMENT

How to Overcome Client-Side Permission Restrictions with Suitelets in NetSuite

Leverage 'Run As Admin' Suitelets to securely access and manipulate external NetSuite records from client-side scripts, bypassing user-specific permission limitations.

Short answer

Client-side scripts in NetSuite operate under the user's permissions, restricting access to records outside the current context. To overcome this, implement a 'Run As Admin' Suitelet as an intermediary. This Suitelet can perform record lookups or updates with elevated permissions, returning the necessary data to the client script, ensuring secure and unrestricted data access.

Scenario

NetSuite client-side scripts are inherently limited by the permissions of the currently logged-in user. This restriction can prevent scripts from reading or writing data to record types other than the one the script is currently executing on. Developers often encounter challenges when a client script needs to interact with external records but faces permission-related failures.

Solution

While User Event scripts can be configured to 'Run As Admin' to access any record without permission restrictions, this capability is not available for client-side scripts. Client-side scripts always execute using the user's permissions. Therefore, when a client-side script requires access to external records, it should utilize an intermediary Suitelet to fetch or update the necessary information. This Suitelet can be set to 'Run As Admin', allowing it to bypass the client user's permissions.

Below is sample code for a SuiteScript 2.1 Suitelet that replicates the functionality of looking up field values, and a corresponding client-side helper function.

  1. Suitelet for Field Lookup (SuiteScript 2.1)

    This Suitelet is designed to receive record type, ID, and field(s) as parameters via a POST request, perform a lookup using search.lookupFields, and return the result as a JSON string. This Suitelet must be deployed with the 'Run As Admin' setting enabled.

javascript
/**
 * @NApiVersion 2.1
 * @NScriptType Suitelet
 */
define(['N/search', 'N/log', 'N/runtime'], function(search, log, runtime) {

    function onRequest(scriptContext) {
        if (scriptContext.request.method === 'POST') {
            var recordType = scriptContext.request.parameters.recordtype;
            var recordId = scriptContext.request.parameters.recordid;
            var recordFields = scriptContext.request.parameters.recordfield;

            log.debug({ title: 'Suitelet Lookup - recordType', details: recordType });
            log.debug({ title: 'Suitelet Lookup - recordId', details: recordId });
            log.debug({ title: 'Suitelet Lookup - recordFields', details: recordFields });

            if (recordType && recordId && recordFields) {
                var columnsToLookup;
                if (recordFields.indexOf(',') !== -1) {
                    columnsToLookup = recordFields.split(',');
                } else {
                    columnsToLookup = recordFields;
                }

                try {
                    var fieldValue = search.lookupFields({
                        type: recordType,
                        id: recordId,
                        columns: columnsToLookup
                    });

                    var output = JSON.stringify(fieldValue);

                    log.debug({ title: 'Suitelet Lookup - output', details: output });
                    scriptContext.response.write(output);

                } catch (e) {
                    log.error({ title: 'Suitelet Lookup Error', details: e });
                    scriptContext.response.write("ERROR: " + e.message);
                }

            } else {
                log.debug({ title: 'Suitelet Lookup - missing parameter', details: 'A missing parameter prevents from looking up value' });
                scriptContext.response.write("0");
            }
        }
    }

    return {
        onRequest: onRequest
    };
});
  1. Client-Side Helper Function (SuiteScript 2.1)

    This helper function, intended for client scripts, constructs the request parameters and calls the deployed Suitelet. It then parses the JSON response from the Suitelet to return the requested field values.

javascript
/**
 * @NApiVersion 2.1
 * @NModuleScope Public
 */
define(['N/url', 'N/https'], function(url, https) {

    function getValueViaSuitelet(recordType, recordId, recordField) {
        var ssuValue = null;

        var fieldsParam;
        if (Array.isArray(recordField)) {
            fieldsParam = recordField.join(",");
        } else {
            fieldsParam = recordField;
        }

        var params = {
            recordtype: recordType,
            recordid: recordId,
            recordfield: fieldsParam
        };

        var suiteletURL = url.resolveScript({
            scriptId: 'customscript_suitelet_lookup_id', // Replace with your Suitelet Script ID
            deploymentId: 'customdeploy_suitelet_lookup_deploy', // Replace with your Suitelet Deployment ID
            returnExternalUrl: false
        });

        try {
            var response = https.post({
                url: suiteletURL,
                body: JSON.stringify(params),
                headers: {
                    'Content-Type': 'application/json'
                }
            });

            if (response.body !== "0" && response.body.indexOf("ERROR") === -1) {
                ssuValue = JSON.parse(response.body);
            } else {
                console.error("Suitelet returned an error or '0': " + response.body);
            }
        } catch (e) {
            console.error("Error calling Suitelet: " + e.message);
        }

        return ssuValue;
    }

    return {
        getValueViaSuitelet: getValueViaSuitelet
    };
});

Implementation Notes:

  • Replace 'customscript_suitelet_lookup_id' and 'customdeploy_suitelet_lookup_deploy' in the client-side helper function with the actual Script ID and Deployment ID of your deployed Suitelet.
  • The Suitelet will always return a JSON object, even if only a single field is requested. The client-side function JSON.parse() handles this conversion.

Expert NetSuite Support

Need help with this NetSuite issue?

SuiteScript Development consulting and configuration support

Talk to a consultant