SuiteTalk TBA Example in C#

Here is an example of a SuiteTalk app in C# that Authenticates using Token Based Authentication (TBA).

SuiteTalkTBADemo

Here is the code:

using System;
using System.Net;
using System.Security.Cryptography;
using SuiteTalkTBADemo.nsWS; // This is a SuiteTalk Web Reference which points to:
// https://%5BYour Accout ID].suitetalk.api.netsuite.com/wsdl/v2016_2_0/netsuite.wsdl

namespace TBADemo
{
class Program
{
private const string account = “[Your Account Here]”;

private const string appID = “[Your App ID here]”;
//CONSUMER KEY
private const string consumerKey = “[Your Consumer Key Here]”;
//CONSUMER SECRET
private const string consumerSecret = “[Your Consumer Secret Here]”;
//TOKEN ID
private const string tokenId = “[Your Token ID Here]”;
//TOKEN SECRET
private const string tokenSecret = “[Your Token Secred Here]”;

private static NetSuiteService service;
protected static Random random = new Random();

static void Main(string[] args)
{

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

DataCenterAwareNetSuiteService service = new DataCenterAwareNetSuiteService(account);
service.Timeout = 1000 * 60 * 60 * 2;

ItemSearchBasic basic = new ItemSearchBasic()
{
internalId = new SearchMultiSelectField()
{
@operator = SearchMultiSelectFieldOperator.anyOf
,
operatorSpecified = true
,
searchValue = new RecordRef[] {
new RecordRef() {
internalId = “53384”
}
}
}
};

service.tokenPassport = createTokenPassport();
SearchResult result = service.search(basic);

if (result.status.isSuccess)
{
Console.WriteLine(“Success!”);
}
else
{
Console.WriteLine(“Failed: “);
foreach (StatusDetail detail in result.status.statusDetail)
{
Console.WriteLine(” ” + detail.message);
}
}

Console.WriteLine();
Console.WriteLine(“Hit enter to close this window.”);
Console.ReadLine();
}

private static TokenPassport createTokenPassport()
{
string nonce = computeNonce();
long timestamp = computeTimestamp();
TokenPassportSignature signature = computeSignature(account, consumerKey, consumerSecret, tokenId, tokenSecret, nonce, timestamp);

TokenPassport tokenPassport = new TokenPassport();
tokenPassport.account = account;
tokenPassport.consumerKey = consumerKey;
tokenPassport.token = tokenId;
tokenPassport.nonce = nonce;
tokenPassport.timestamp = timestamp;
tokenPassport.signature = signature;
return tokenPassport;
}

private static string computeNonce()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] data = new byte[20];
rng.GetBytes(data);
int value = Math.Abs(BitConverter.ToInt32(data, 0));
return value.ToString();
}

private static long computeTimestamp()
{
return ((long) (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds);
}

private static TokenPassportSignature computeSignature(string compId, string consumerKey, string consumerSecret,
string tokenId, string tokenSecret, string nonce, long timestamp)
{
string baseString = compId + “&” + consumerKey + “&” + tokenId + “&” + nonce + “&” + timestamp;
string key = consumerSecret + “&” + tokenSecret;
string signature = “”;
var encoding = new System.Text.ASCIIEncoding();
byte[] keyBytes = encoding.GetBytes(key);
byte[] baseStringBytes = encoding.GetBytes(baseString);
using (var hmacSha1 = new HMACSHA1(keyBytes))
{
byte[] hashBaseString = hmacSha1.ComputeHash(baseStringBytes);
signature = Convert.ToBase64String(hashBaseString);
}
TokenPassportSignature sign = new TokenPassportSignature();
sign.algorithm = “HMAC-SHA1”;
sign.Value = signature;
return sign;
}

}

class DataCenterAwareNetSuiteService : NetSuiteService
{
public DataCenterAwareNetSuiteService(string account)
: base()
{
System.Uri originalUri = new System.Uri(this.Url);
DataCenterUrls urls = getDataCenterUrls(account).dataCenterUrls;
Uri dataCenterUri = new Uri(urls.webservicesDomain + originalUri.PathAndQuery);
this.Url = dataCenterUri.ToString();
}
}
}

10 thoughts on “SuiteTalk TBA Example in C#

    1. Jeremy says:

      Did anyone figure out the “Invalid Login Attempt” issue? I’m able to make an initial call and do a search or create a transaction, but if I try to make a second call I receive the “Invalid Login Attempt” error.

      Like

  1. Search for SuiteTalk in the search box in my blog. I’ve written a number of articles on it. It’s been a while since I was in that code. However, I remember there are issues with allowing TBA, setting up security associated with the account you’re using and avoiding an account that requires 2-factor authentication. Hope that helps.

    Like

  2. Paul Smietan says:

    Kevin, awesome example code! Aside from updating the keys and encryption protocol I got everything to work! Thank you!!!

    Like

  3. Don Kwitty says:

    Kevin, I’m having trouble with “invalid signature’ errors. I see that you commented “… a token only works once!” — but your code above doesn’t demonstrate anything regarding getting new tokens. Quite the opposite, you have constants for the token ID and token secret — just like all other examples I have seen. Could you please clarify? Thanks!

    Like

  4. Hi Don, the 2 lines of code are where the token is created and used:

    service.tokenPassport = createTokenPassport();
    SearchResult result = service.search(basic);

    The first line creates the token/passport, which can only be used for one service call. The second line is the service call. Every time you make a service call you must get a fresh token/passport.

    Like

Leave a comment