Updating a SOAP Web Services Integration to Send Token-Based Authentication Details

The following procedure and Java code snippets show one way of updating an application to include token-based authentication (TBA) details.

You use the TokenPassport and TokenPassportSignature complex types to send TBA details. These types are defined in the Core XSD. See also TokenPassport Complex Type.

Note that this example uses request-level credentials. When using TBA, your SOAP request must be structured this way. The login operation is not supported. For additional requirements, see Requirements for Using Token-Based Authentication.

Note:

If a request uses token-based authentication, your request must not include an application ID. If you include an application ID with a request that uses TBA, the request fails.

To update a SOAP web services integration to send token-based authentication details:

  1. Add logic for creating an RFC 2104-compliant signature. For example, you could add a method that has three arguments: a base string, a key, and an algorithm. Later, you could call this method by passing values specific to your request. (For details on the data needed to create the correct base string and key values, see TokenPassportSignature.)

    This example does not require the use of a third-party library. However, the javax.crypto package is used.

    Warning:

    The end of support for the HMAC-SHA1 signature method targeted for 2021.2 has been postponed. However, the algorithm used by the HMAC-SHA1 signature method is no longer considered secure. You should update your integrations to use the HMAC-SHA256 signature method as soon as possible.

                    protected String computeShaHash(String baseString, String key, String algorithm) throws Exception {
    
       byte[] bytes = key.getBytes();
       SecretKeySpec mySigningKey = new SecretKeySpec(bytes, algorithm);
    
       Mac messageAuthenticationCode = Mac.getInstance(algorithm);
    
       messageAuthenticationCode.init(mySigningKey);
    
       byte[] hash = messageAuthenticationCode.doFinal(baseString.getBytes());
    
       String result = new String(java.util.Base64.getEncoder().encode(hash));
    
       return result;
    } 
    
                  
  2. Using variables that reflect data specific to your request, add logic for calling the computeShaHash method you created in step 1 to calculate a signature.

                    public String computeSignature(
          String account,
          String consumerKey,
          String consumerSecret,
          String token,
          String tokenSecret,
          String nonce,
          Long timeStamp
    ) throws Exception {
       String baseString = account + "&" + consumerKey + "&" + token + "&" + nonce + "&" + timeStamp;
    
       String key = consumerSecret + '&' + tokenSecret;
    
       String signature = computeShaHash(baseString, key, "HmacSHA256");
    
       return signature;
    } 
    
                  
  3. Add logic for creating a TokenPassport SOAP header.

                    @Override
       public void setTokenPassport(
             String account,
             String consumerKey,
             String token,
             String nonce,
             Date timestamp,
             String signatureAlgorithm,
             String signature
       ) throws Exception
       {
          initPort();
          if(m_tokenPassport == null)
          {
             m_tokenPassport = new TokenPassport();
             ((Stub) m_port).setHeader( m_sMessagesUrn, "tokenPassport", m_tokenPassport);
          }
          m_tokenPassport.setAccount(account);
          m_tokenPassport.setConsumerKey(consumerKey);
          m_tokenPassport.setToken(token);
          m_tokenPassport.setNonce(nonce);
          m_tokenPassport.setTimestamp(timestamp.getTime());
          TokenPassportSignature signatureElement = new TokenPassportSignature();
          signatureElement.setAlgorithm(signatureAlgorithm);
          signatureElement.set_value(signature);
          m_tokenPassport.setSignature(signatureElement);
       } 
    
                  
  4. To add your token-based authentication credentials to a request, add logic similar to the following. Notice that in this example, the exact variables are defined. This example calls the computeSignature method from step 3 to create the signature. It also sets the values in the fields of the TokenPassport object created in step 4. These values are later visible in the SOAP request. By contrast, the consumer secret and token secret are not explicitly part of the SOAP request. They are represented only in the signature.

                    public void testGetServerTimeWithTBA() throws Exception
    {
    // Constants
       String sCompId = "1234567";
       String consumerKey = "71cc02b731f05895561ef0862d71553a3ac99498a947c3b7beaf4a1e4a29f7c4";
       String consumerSecret = "7278da58caf07f5c336301a601203d10a58e948efa280f0618e25fcee1ef2abd";
       String tokenId = "89e08d9767c5ac85b374415725567d05b54ecf0960ad2470894a52f741020d82";
       String tokenSecret = "060cd9ab3ffbbe1e3d3918e90165ffd37ab12acc76b4691046e2d29c7d7674c2";
       String algorithm = SignatureAlgorithm._HMAC_SHA256;
    
    // Nonce and timeStamp must be unique for each request. Also, make sure that the nonce value you 
    // generate does not contain special characters.
    
       String nonce = RandomStringUtils.randomAlphanumeric(20);
       Long timeStamp = System.currentTimeMillis() / 1000L;
    
       String signature = c.computeSignature(sCompId, consumerKey, consumerSecret, tokenId, tokenSecret, nonce, timeStamp);
    
    // create and set TokenPassport SOAP Header
    // notice - no secrets are included in this call
          c.setTokenPassport(
                sCompId,
                consumerKey,
                tokenId,
                nonce,
                new Date(timeStamp),
                algorithm,
                signature);
    
          c.getPort().getServerTime();
       } 
    
                  

    The following example shows how the resulting SOAP request should appear.

                    <ns:tokenPassport soap:actor="http://schemas.xmlsoap.org/soap/actor/next" soap:mustUnderstand="0" xmlns:ns="urn:messages_2017_1.platform.webservices.netsuite.com">
       <ns:account>1234567</ns:account>
       <ns:consumerKey>71cc02b731f05895561ef0862d71553a3ac99498a947c3b7beaf4a1e4a29f7c4</ns:consumerKey>
       <ns:token>89e08d9767c5ac85b374415725567d05b54ecf0960ad2470894a52f741020d82</ns:token>
       <ns:nonce>6obMKq0tmY8ylVOdEkA1</ns:nonce>
       <ns:timestamp>1439829974</ns:timestamp>
       <ns:signature algorithm="HMAC_SHA256">fzGxUBu6SZvGqv5hk8P4ou2DPthSxXtJ4zJIeCBQK5A=</ns:signature>
    </ns:tokenPassport> 
    
                  
    Note:

    For the signature algorithm value, you can use either a hyphen or an underscore. (For example, HMAC-SHA256 or HMAC_SHA256). However, the underscore is only acceptable in a SOAP web services request. SOAP web services integrations use the NetSuite TokenPassport complex type. The underscore is used by the SignatureAlgorithm enumeration, which is defined in the core types XSD.

    Important:

    Only a hyphen is acceptable in the algorithm value for RESTlets and REST web services. RESTlets and REST web services integrations use the OAuth protocol, which requires the use of a hyphen, for example, HMAC-SHA256. For more information, see RESTlet Authentication and Authentication and Session Management for REST Web Services.

Related Topics

Requirements for Using Token-Based Authentication
Regenerating a Consumer Key and Secret
TokenPassport Complex Type
SOAP Web Services Governance for Token-Based Authentication
Token-Based Authentication Errors in SOAP Web Services

General Notices