0

I'm trying to make a POST request to an API, and have successfully done this in Postman. Now, because Postman offers code snippets, I can just copy-paste this to a C# application and get the exact same result.

Here's the problem: The auth expires. If I make a call in Postman and copy the nonce, signature, and timestamp values into my application and use it that way, it works fine for a few minutes. Eventually it expires and the call doesn't work, it returns a 0005. Therefore, I have to generate the signature, nonce, and timestamp values myself, in my application.

I already spent so many hours trying to do this but I can't figure out why it's not working. I tried several ways, but the one that seems to have gotten me the furthest is the below:

The following code is given by Postman after successfully making the call (using RestSharp):

var client = new RestClient("api-url.com");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "OAuth oauth_consumer_key=\"xxxx5004bbf7xxxxxx3d3e15633f01xx\",oauth_token=\"xxx894c7c76c4axxx93d833804615xxx\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1605587985\",oauth_nonce=\"TNTCB73am0T\",oauth_version=\"1.0\",oauth_signature=\"6P7uvtxxxsEv1pz6JfxxxxlEmDY%3D\"");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\r\n    \"start\": {\"from\": 1604542428000, \"to\": 1605147228000},\r\n    \"status\": [\"CLOSE\"]\r\n}\r\n",  ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

Then, I use the following to get the Base64 of the signature string

public static string GetSignatureBaseString(string TimeStamp, string Nonce)
{
    //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 + "&";

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

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

    //5.append parameter string to the output string.
    Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("oauth_consumer_key=" + Settings.SettingsManager.consumer_key);
    Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("&oauth_token=" + Settings.SettingsManager.access_token);
    Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("&oauth_signature_method=" +"HMAC-SHA1");
    Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("&oauth_timestamp=" + TimeStamp);
    Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("&oauth_nonce=" + Nonce);
    Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("&oauth_version=" + "1.0");

    return Signature_Base_String;
}

Finally, to get the sha1 hash

public static string GetSha1Hash(string key, string message)
{
    var encoding = new System.Text.ASCIIEncoding();

    byte[] keyBytes = encoding.GetBytes(key);
    byte[] messageBytes = encoding.GetBytes(message);

    string Sha1Result = string.Empty;

    using (HMACSHA1 SHA1 = new HMACSHA1(keyBytes))
    {
        var Hashed = SHA1.ComputeHash(messageBytes);
        Sha1Result = Convert.ToBase64String(Hashed);
    }

    return Sha1Result;
}

The OAuth 1.0 string it outputs and sends to the server is as follows:

OAuth oauth_consumer_key="c3e75004bbfxxxxxxx5f0104",oauth_token="e90xxxxxx38046158d3",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1605588743",oauth_nonce="MTYwNTU4ODc0Mw%3D%3D",oauth_version="1.0",oauth_signature="4jKad%2xxxxxxSV%xxxxxxxxxxxMP%2FI%3D"

The way I combine this is simply to replace the keys in the successful Postman call with a string format {0} {1} {2} etc with the values generated by the two functions: key & access token is fine, timestamp I get from the current time obv, nonce is the base64 of the timestamp, and then the signature is the hash on the base64 signature from funct1 using secret & tokensecret.

Which looks a lot like the Postman once (except that their nonce is always very short compared to mine but I assume that's not related to the problem).

Can anyone spot what I'm doing wrong?

Edit: Extra code

The way I use all the above:

var timeStamp = (System.Convert.ToInt32((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds)).ToString();
var nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(timeStamp)).ToString();
SortedDictionary<string, string> @params = new SortedDictionary<string, string>();
@params.Add("application/json", "{" + Constants.vbCrLf + "    \"start\": {\"from\": 1604542428000, \"to\": 1605147228000}," + Constants.vbCrLf + "    \"status\": [\"CLOSE\"]" + Constants.vbCrLf + "}" + Constants.vbCrLf);
string b64sig = GetSignatureBaseString(timeStamp, nonce);
string signature = GetSha1Hash("secret-key", b64sig);

Then I insert all the values I have into the OAuth string and make the request. It returns a 0005 auth error. About the body params, I need to have these in order to get a response. This works fine if I just use the Postman nonce, timestamp and signature so I believe it's not related to the problem though. I don't need to include the body params to generate a signature right?

ItsPete
  • 2,363
  • 3
  • 27
  • 35
sebjsv
  • 1
  • 3
  • Can you share the code which generates timestamp and nonce? Also how you generating signature from SingagutureBaseString? – Chetan Nov 17 '20 at 05:25
  • @ChetanRanpariya Hi, thank you for the reply. I use the following to generate timestamp: var timeStamp = (System.Convert.ToInt32((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds)).ToString(); – sebjsv Nov 17 '20 at 05:34
  • @ChetanRanpariya The signature is generated by escaping the result of GetSha1Hash on the signature64basestring using secret-key. EscapeDataString(GetSha1Hash("secret-key", b64sig)). It's messy in a comment so I will add it all to the OP. – sebjsv Nov 17 '20 at 05:38
  • The way you are generating signature base string is not correct... you can refer documentation from twitter [here](https://developer.twitter.com/en/docs/authentication/oauth-1-0a/creating-a-signature) for how to generate base string. – Chetan Nov 17 '20 at 05:45
  • And once you generate proper signature base ,you need to generate signature using both clientsecret and tokensecret if you have token secret or only use client secret to generatethe signature.. – Chetan Nov 17 '20 at 05:47
  • You can refer https://stackoverflow.com/questions/35677711/generate-oauth1-signature-in-c-sharp too.. – Chetan Nov 17 '20 at 05:48
  • Does this answer your question? [Generate OAuth1 signature in C#](https://stackoverflow.com/questions/35677711/generate-oauth1-signature-in-c-sharp) – Chetan Nov 17 '20 at 05:48
  • This is one of the posts I have been trying to adapt as well, but can't get it to work. I tried from zero again with that link while also reading the Twitter documentation, but cannot get it to work. I tried copy pasting the two code snippets exactly as they are, declaring my keys/secrets in variables and simply plugging it in. I then got the current timestamp and a nonce, created the baseSignature through code snippet #1, and hashed it with escped secretkey + & + escaped tokensecret. I then inserted these values into the request code snippet that Postman gives (which works with their values) – sebjsv Nov 17 '20 at 08:28
  • And that also gives 0005... – sebjsv Nov 17 '20 at 08:28

0 Answers0