NetSuite: RESTlet Token Access with C#

Updated to use HMAC-SHA256 for 2022.

The first time I needed to authenticate using tokens in order to interact with a RESTlet, I found myself trawling the web for code samples as the official documentation doesn’t quite explain all of the details. I pulled together some information from a few places, and now these resulting code samples are my go-to for any C# work.

Gathering Materials

First of all, you will need this OAuth class. [Out of date now that SHA1 is deprecated. See the link at the end for an up-to-date version] In case the link breaks I will leave a download at the end. It is a short class that you could likely replace with your own implementation if you really wanted, and it just provides some basic OAuth functionality.

You will need the following pieces of information:

  • Netsuite Realm – This is your business ID. You can see it in every url, and you can find it more formally under Setup > Integration > Web Services Preferences, where it is labelled Account ID. This will have _SB1 or something similar in the name when you are using a sandbox – do include that part.
  • Consumer ID & Consumer Secret – These are shown to you one time when you create the integration.
  • Token ID & Token Secret – These are shown to you one time when you create the access token. (Setup > Users/Roles > Access Tokens)
  • The URL of your RESTlet, including deploy_id.

Crafting a GET Request

I think the code is plain enough to speak for itself:

using System;
using System.IO;
using System.Net;
using Newtonsoft.Json;

// Namespace / class stuff omitted.

string NS_realm = "1234567" // 1234567_SB1 for sandbox
string url = "https://1234567.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=1";

HttpWebRequest request = null;
HttpWebResponse response = null;

String header = "Authorization: OAuth ";

try
{
	string consumer_id = "YOUR_CONSUMER_ID"; // (Also called Consumer Key)
	string consumer_secret = "YOUR_CONSUMER_SECRET";
	string token_id = "YOUR_TOKEN_ID";
	string token_secret = "YOUR_TOKEN_SECRET";

	Uri uri = new Uri((url + "&YOUR_QUERY_STRING")); // Omit the query string part if you don't need it.

	OAuthBase req = new OAuthBase();

	string normalized_url;
	string normalized_params;

	string nonce = req.GenerateNonce();
	string time = req.GenerateTimeStamp();

	string signature = req.GenerateSignature(uri, consumer_id, consumer_secret, token_id, token_secret, "GET",
						 time, nonce, out normalized_url, out normalized_params);

	// URL encode any + characters generated in the signature
	if (signature.Contains("+"))
	{
		signature = signature.Replace("+", "%2B");
	}
	
	// Construct the OAuth header		
	header += "oauth_signature=\"" + signature + "\",";
	header += "oauth_version=\"1.0\",";
	header += "oauth_nonce=\"" + nonce + "\",";
	header += "oauth_signature_method=\"HMAC-SHA256\",";
	header += "oauth_consumer_key=\"" + consumer_id + "\",";
	header += "oauth_token=\"" + token_id + "\",";
	header += "oauth_timestamp=\"" + time + "\",";
	header += "realm=\"" + NS_realm + "\"";

}
catch (Exception q)
{
	Console.WriteLine("Configuration error. Check tokens and NBN.");
	return null;
}

try
{
	request = (HttpWebRequest)WebRequest.Create((url + "&YOUR_QUERY_STRING"));
	request.ContentType = "application/json";
	request.Method = "GET";
	request.Headers.Add(header);
}
catch (Exception e)
{
	Console.WriteLine("Couldn't generate request. Check RESTlet URL and NBN.");
	return null;
}

try
{
	WebResponse response = request.GetResponse();
	httpResponse = (HttpWebResponse)response;

	Stream resStream = httpResponse.GetResponseStream();
	StreamReader sr = new StreamReader(resStream);
	var result = sr.ReadToEnd();

	MyObject ResultObject = Newtonsoft.Json.JsonConvert.DeserializeObject<MyObject>((string)result);
	return ResultObject;
}
catch (UriFormatException)
{
	Console.WriteLine("Error forming request. Check tokens, URL, and NBN details.");
	return null;
}
catch (Exception e)
{
	Console.WriteLine("Server or connection error:\n" + e.ToString());
	return null;
}

As you can see, once you get the OAuth format specifics just right, it isn’t actually overly complex.

Note that the signature is valid only for a single request, and so the nonce, time, and signature must be regenerated each time.

Crafting a POST Request

The code is very similar, but note the changing of two occurrences of “GET” to “POST”, the removal of query strings, and the additional need to write a body.

using System;
using System.IO;
using System.Net;
using Newtonsoft.Json;

// Namespace / class stuff omitted.

string NS_realm = "1234567" // 1234567_SB1 for sandbox
string url = "https://1234567.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=1";

HttpWebRequest request = null;
HttpWebResponse response = null;

String header = "Authorization: OAuth ";

try
{
	string consumer_id = "YOUR_CONSUMER_ID"; // (Also called Consumer Key)
	string consumer_secret = "YOUR_CONSUMER_SECRET";
	string token_id = "YOUR_TOKEN_ID";
	string token_secret = "YOUR_TOKEN_SECRET";

	Uri uri = new Uri(url);

	OAuthBase req = new OAuthBase();

	string normalized_url;
	string normalized_params;

	string nonce = req.GenerateNonce();
	string time = req.GenerateTimeStamp();

	string signature = req.GenerateSignature(uri, consumer_id, consumer_secret, token_id, token_secret, "POST",
						 time, nonce, out normalized_url, out normalized_params);

	// URL encode any + characters generated in the signature
	if (signature.Contains("+"))
	{
		signature = signature.Replace("+", "%2B");
	}
	
	// Construct the OAuth header		
	header += "oauth_signature=\"" + signature + "\",";
	header += "oauth_version=\"1.0\",";
	header += "oauth_nonce=\"" + nonce + "\",";
	header += "oauth_signature_method=\"HMAC-SHA256\",";
	header += "oauth_consumer_key=\"" + consumer_id + "\",";
	header += "oauth_token=\"" + token_id + "\",";
	header += "oauth_timestamp=\"" + time + "\",";
	header += "realm=\"" + NS_realm + "\"";

}
catch (Exception q)
{
	Console.WriteLine("Configuration error. Check tokens and NBN.");
	return null;
}

try
{
	request = (HttpWebRequest)WebRequest.Create(url);
	request.ContentType = "application/json";
	request.Method = "POST";
	request.Headers.Add(header);

	int cust_id = 45;
	int order_no = 234354;
	int quantity = 5;

	using (var streamWriter = new StreamWriter(request.GetRequestStream()))
	{
		// A sample JSON POST body.
		string json = "{\"customer_id\":\"" + cust_id + "\"," +
			      "\"order_number\":\"" + order_no + "\"," +
			      "\"quantity\":\"" + quantity + "\"," +
			      "\"}";
		
		streamWriter.Write(json);
	}
}
catch (Exception e)
{
	Console.WriteLine("Couldn't generate request. Check RESTlet URL and NBN.");
	return null;
}

try
{
	WebResponse response = request.GetResponse();
	httpResponse = (HttpWebResponse)response;

	Stream resStream = httpResponse.GetResponseStream();
	StreamReader sr = new StreamReader(resStream);
	var result = sr.ReadToEnd();

	MyObject ResultObject = Newtonsoft.Json.JsonConvert.DeserializeObject<MyObject>((string)result);
	return ResultObject;
}
catch (UriFormatException)
{
	Console.WriteLine("Error forming request. Check tokens, URL, and NBN details.");
	return null;
}
catch (Exception e)
{
	Console.WriteLine("Server or connection error:\n" + e.ToString());
	return null;
}

Thanks for reading! I hope this provided you a nice easy starting point.

Download links:
OAuthBase.cs
Netsuite.cs