Token-based Authentication with Netsuite's PHP Toolkit


Netsuite will soon be making 2FA required for integration accounts. This means your scripts that connect to Netsuite will stop working if they do not use token-based authentication (TBA).

The following is a way of doing TBA to remove the 2FA requirements for those using PHP with Netsuite.

You will need 5 items:

  1. Your current Netsuite PHP toolkit
  2. Consumer Key
  3. Consumer Secret
  4. Token Key
  5. Token Secret

Your standard Netsuite script may look something like this:

$service = new NetSuiteService();

// Change phone number
$nscust = new Customer();
$nscust->internalId = '123456';
$nscust->phone = "(402) 123-4567";

// Send request
$updateRequest = new UpdateRequest();
$updateRequest->record = $nscust;
$updateResponse = $service->update( $updateRequest );
print_r( $updateResponse->writeResponse );

Running the above script should have a successful update message returned to you. In the SOAP request log (which you can enable by creating a folder named nslog in the PHP toolkit library), you will see that it is using user credentials and not token-based authentication.

To start using token-based authentication, we'll first add in our keys to the NSconfig.php file with your own consumer keys:

define("NS_CONSUMER_KEY", "12345aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
define("NS_CONSUMER_SECRET", "12345aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
define("NS_TOKEN_KEY", "12345aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
define("NS_TOKEN_SECRET", "12345aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

Create a file NStba.php with Netsuite's provided example for TBA:

<?php

class MyTokenPassportGenerator implements iTokenPassportGenerator
{
    public function generateTokenPassport() {
        $consumer_key = NS_CONSUMER_KEY; // Consumer Key shown once on Integration detail page
        $consumer_secret = NS_CONSUMER_SECRET; // Consumer Secret shown once on Integration detail page
        // following token has to be for role having those permissions: Log in using Access Tokens, Web Services
        $token = NS_TOKEN_KEY; // Token Id shown once on Access Token detail page
        $token_secret = NS_TOKEN_SECRET; // Token Secret shown once on Access Token detail page
        
        $nonce = $this->generateRandomString();// CAUTION: this sample code does not generate cryptographically secure values
        $timestamp = time();

        $baseString = urlencode(NS_ACCOUNT) ."&". urlencode($consumer_key) ."&". urlencode($token) ."&". urlencode($nonce) ."&". urlencode($timestamp);
        $secret = urlencode($consumer_secret) .'&'. urlencode($token_secret);
        $method = 'sha1'; //can be sha256   
        $signature = base64_encode(hash_hmac($method, $baseString, $secret, true));
        
        $tokenPassport = new TokenPassport();
        $tokenPassport->account = NS_ACCOUNT;
        $tokenPassport->consumerKey = $consumer_key;
        $tokenPassport->token = $token;
        $tokenPassport->nonce = $nonce;                                    
        $tokenPassport->timestamp = $timestamp; 
        $tokenPassport->signature = new TokenPassportSignature();
        $tokenPassport->signature->_ = $signature;
        $tokenPassport->signature->algorithm = "HMAC-SHA1";  //can be HMAC-SHA256
        
        return $tokenPassport;
    }

    /**
     * Not related to Token-Based Authentication, just displaying responses in this sample.
     * It is assumed (and not checked) that $timeResponse is a response of getServerTime operation.
     */
    public static function echoResponse($timeResponse) {
        if (!$timeResponse->getServerTimeResult->status->isSuccess) {
            echo "GET ERROR\n";
        } else {
            echo "GET SUCCESS, time:". $timeResponse->getServerTimeResult->serverTime. "\n";
        }
    }

    // CAUTION: it does not generate cryptographically secure values
    private function generateRandomString() {
        $length = 20;
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $charactersLength = strlen($characters);
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, $charactersLength - 1)]; // CAUTION: The rand function does not generate cryptographically secure values
            // Since PHP 7 the cryptographically secure random_int can be used
        }
        // echo value just in this sample to show when and how many times called
        // echo "New nonce for TokenPassport: ". $randomString. "\n";
        return $randomString;
    }
}

The above script is what will be doing all the authentication work for us.

Now we go to the PHP Toolkit and automatically attach the token generator with each request.

Include our new file near the top of NSPHPCLient.php:

require_once "NStba.php";

In the same file, around line 252 after it does a check for NSAPPID, add the following to attach the token generator:

if (defined('NS_CONSUMER_KEY')) {
    $generator = new MyTokenPassportGenerator();
    $this->setTokenGenerator($generator);
}

Now if you run the initial phone-number-edit script, you will see that the SOAP request is now using tokens instead of user credentials.

Back to Reads