0

I am trying to call Netsuite api using oath 1.0 from C#.

It works in postman. used postman generated values (timestamp, nonce, signagurebase) in c# then it worked. HMAC-SHA256 is being here.

Generated Signature in code doesn't work, getting "INVALID_LOGIN_ATTEMPT" message.

Main method:

    string consumerKey = "******";
    string TokenId = "******";
    string ConsumerSecret = "******";
    string TokenSecret = "******";

    string realm = "****";
    string signatureMethod = "HMAC-SHA256";

    string apiUrl = "https://test-test.api.netsuite.com/app/site/hosting/restlet.nl?script=941&deploy=1&FC=SGD&TC=USD&ED=02/11/2022";
    string baseUrl = "https://test-sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl";

    public void run()
    {
        var timeStamp = ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
        var nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(timeStamp));

        var signatureBase = GetSignatureBaseString(timeStamp, nonce);
        var oauthSignature = encryptSignatureBase(signatureBase, ConsumerSecret, TokenSecret);

        var client = new RestClient(apiUrl);
        var request = new RestRequest("", Method.Get);

        //test with postman values, which is working fine.
        //timeStamp = "1669601987";
        //nonce = "5D1TNfnx5oW";
        //oauthSignature = "C8TXCdaT1If0Od6BU4T8yqukRjFSAz%2BtrO3cZi8lUvw%3D";

        var oauthStr = $"OAuth realm =\"{realm}\",oauth_consumer_key=\"{consumerKey}\",oauth_token=\"{TokenId}\",oauth_signature_method=\"HMAC-SHA256\",oauth_timestamp=\"{timeStamp}\",oauth_nonce=\"{nonce}\",oauth_version=\"1.0\",oauth_signature=\"{oauthSignature}\"";
   
        request.AddHeader("Authorization", oauthStr);
        request.AddHeader("Content-Type", "application/json");
        request.AddHeader("Cookie", "NS_ROUTING_VERSION=LAGGING");
        request.AddParameter("application/json", "{}", ParameterType.RequestBody);

        var response = client.Execute(request);
        Console.WriteLine(response.Content);
    }

generateSignature base string

    string GetSignatureBaseString(string timestamp, string nounce)
    {
        //1.Convert the HTTP Method to uppercase and set the output string equal to this value.
        string Signature_Base_String = "GET";
        Signature_Base_String = Signature_Base_String.ToUpper();

        //2.Append the ‘&’ character to the output string.
        Signature_Base_String = Signature_Base_String + "&";

        SortedDictionary<string, string> paramStrings = new SortedDictionary<string, string>();
        paramStrings.Add("script", "941");
        paramStrings.Add("deploy", "1");
        paramStrings.Add("FC", "SGD");
        paramStrings.Add("TC", "USD");
        paramStrings.Add("ED", "02/11/2022");

        //3.Percent encode the URL and append it to the output string.
        string PercentEncodedURL = Uri.EscapeDataString(baseUrl);
        Signature_Base_String = Signature_Base_String + PercentEncodedURL;

        //4.Append the ‘&’ character to the output string.
        Signature_Base_String = Signature_Base_String + "&";

        //5.append OAuth parameter string to the output string.
        var parameters = new SortedDictionary<string, string>
        {
            {"oauth_consumer_key", consumerKey},
            {"oauth_token", TokenId },
            {"oauth_signature_method", signatureMethod},
            {"oauth_timestamp", timestamp},
            {"oauth_nonce", nounce},
            {"oauth_version", "1.0"}
        };

        //6.append parameter string to the output string.
        foreach (KeyValuePair<string, string> elt in paramStrings)
        {
            parameters.Add(elt.Key, elt.Value);
        }

        bool first = true;
        foreach (KeyValuePair<string, string> elt in parameters)
        {
            if (first)
            {
                Signature_Base_String = Signature_Base_String + Uri.EscapeDataString(elt.Key + "=" + elt.Value);
                first = false;
            }
            else
            {
                Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("&" + elt.Key + "=" + elt.Value);
            }
        }

        return Signature_Base_String;
    }

encrypt using Mac-sha256

   public string encryptSignatureBase(string signatureBase, string consumerSecret, string tokenSecret)
    {
        HMACSHA256 hmacsha1 = new HMACSHA256();
        hmacsha1.Key = Encoding.ASCII.GetBytes(string.Format("{0}&{1}", UrlEncode(consumerSecret), UrlEncode(tokenSecret)));

        byte[] dataBuffer = Encoding.ASCII.GetBytes(signatureBase);
        byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);

        return Convert.ToBase64String(hashBytes);
    }

    string unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";

    protected string UrlEncode(string value)
    {
        StringBuilder result = new StringBuilder();

        foreach (char symbol in value)
        {
            if (unreservedChars.IndexOf(symbol) != -1)
                result.Append(symbol);
            else
                result.Append('%' + String.Format("{0:X2}", (int)symbol));
        }
        return result.ToString();
    }
anand
  • 307
  • 3
  • 14

2 Answers2

2

I used restSharp library itself for Signature it worked.

var client = new RestClient(netsuite_base_url2);
client.AddDefaultQueryParameter("script", "941");
client.AddDefaultQueryParameter("deploy", "1");
client.AddDefaultQueryParameter("FC", "SGD");
client.AddDefaultQueryParameter("TC", "USD");
client.AddDefaultQueryParameter("ED", "02/11/2022");

var oAuth1 = OAuth1Authenticator.ForAccessToken(
                consumerKey: consumerKey,
                consumerSecret: ConsumerSecret,
                token: TokenId,
                tokenSecret: TokenSecret,
                OAuthSignatureMethod.HmacSha256);

oAuth1.Realm = realm; // if Realm has otherwise ignore

client.Authenticator = oAuth1;

var request = new RestRequest("", Method.Get);
request.AddHeader("Content-Type", "application/json");
RestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

Console.ReadLine();
anand
  • 307
  • 3
  • 14
  • I spent way too much time on their broken postman templates! Thank you - this worked. Although latest restSharp requires the following authenticator setup: var options = new RestClientOptions("https://.suitetalk.api.netsuite.com/services/rest") { Authenticator = oAuth1 }; var client = new RestClient(options); – diegorodny Aug 14 '23 at 02:17
0

I face the same issue some time ago, I have to order the netSuiteAuthorization like this

if (signature.Contains("+"))
        {
            signature = signature.Replace("+", "%2B");
        }
        String header = "Authorization: OAuth ";
        header += "oauth_signature=\"" + signature + "\",";
        header += "oauth_version=\"1.0\",";
        header += "oauth_nonce=\"" + nonce + "\",";
        header += "oauth_signature_method=\"HMAC-SHA256\",";
        header += "oauth_consumer_key=\"" + ckey + "\",";
        header += "oauth_token=\"" + tkey + "\",";
        header += "oauth_timestamp=\"" + timestamp + "\",";
        header += "realm=\"+ReamlV+\"";
        
wozzarvl
  • 304
  • 4
  • 17
  • I use same order as generated from postman code snippet. it worked. when I use my generated signature base, it fails. url contains some params. Parameter, parameter could be the problem? I modified in the code in main question. could you review it? – anand Nov 30 '22 at 07:39
  • tried your suggestion too, didn't help. OAuth oauth_signature="****", oauth_version="1.0", oauth_nonce="****",oauth_signature_method="HMAC-SHA256",oauth_consumer_key="****",oauth_token="****",oauth_timestamp="1669794353",realm ="**" – anand Nov 30 '22 at 07:48