Error: client and server signatures do not match

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MarkQB
    New Member
    • Mar 2022
    • 1

    Error: client and server signatures do not match

    Good morning to all. I need help in finding the solution to this error.
    I am building integration with ShopSite.com. They have an API.
    The sample code given is in PHP code.
    I don't know PHP, but I have tried and successfully generated the access_token (Step 1)
    Now I am trying to download the orders and getting this below error

    {
    "error": "access_denied" ,
    "error_descript ion": "client and server signatures do not match"
    }

    Below is my C# code:

    Code:
    string DownloadOrders()
            {
                Random random = new Random();
                string secretKey = "D054-134B-9959-3FB2";
                string token = "MTY0NzUwMTIyOHx3b29kcGFydHN8NnxGaXNoYm93bHw3NzF8";
                string downloadUrl = "https://www.example.com/cgi-woodparts/sb/db_xml.cgi";
                string port = "443";
                string urlPath = "/cgi-woodparts/sb/db_xml.cgi";
                string nonce = random.Next(123400, 9999999).ToString();
                Int32 unixTimestamp = (int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
    
                StringBuilder signatureBuilder = new StringBuilder();
                signatureBuilder.Append(token).Append(Environment.NewLine);
                signatureBuilder.Append(unixTimestamp).Append(Environment.NewLine);
                signatureBuilder.Append(nonce).Append(Environment.NewLine);
                signatureBuilder.Append(Environment.NewLine);
                signatureBuilder.Append("POST").Append(Environment.NewLine);
                Uri myUri = new Uri(downloadUrl);
                string domain = myUri.Host;
                signatureBuilder.Append(domain).Append(Environment.NewLine);
                signatureBuilder.Append(port).Append(Environment.NewLine);
                signatureBuilder.Append(urlPath).Append(Environment.NewLine);
                signatureBuilder.Append("clientApp=1").Append(Environment.NewLine);
                signatureBuilder.Append("dbname=orders").Append(Environment.NewLine);
                signatureBuilder.Append("startdate=11%2F01%2F2021").Append(Environment.NewLine);
                signatureBuilder.Append("version=14.0").Append(Environment.NewLine);
    
                string sSign = signatureBuilder.ToString();
                string signature = GetHMAC(sSign, secretKey);
    
                string orderUrl = downloadUrl;
                var client = new RestClient(orderUrl);
                client.Timeout = -1;
                var request = new RestRequest(Method.POST);
                request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
                request.AddParameter("token", token);
                request.AddParameter("timestamp", unixTimestamp);
                request.AddParameter("nonce", nonce);
                request.AddParameter("signature", signature);
    
                request.AddParameter("clientApp", "1");
                request.AddParameter("dbname", "orders");
                request.AddParameter("startdate", "11%2F01%2F2020");
                request.AddParameter("version", "14.0");
    
                var response = client.Execute(request);
                return response.Content;
            }
    Code:
    private string GetHMAC(string text, string key)
           {
                key = key ?? "";
                using (var hmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(key)))
                {
                    var hash = hmacsha1.ComputeHash(Encoding.UTF8.GetBytes(text));
                    return Convert.ToBase64String(hash);
                }
            }
    Below is the PHP code I am referring

    Code:
    $json = json_decode($json, true);
     $nonce2 = mt_rand(10000000,99999999); # nonce for download request
     $timestamp = time();                  # UNIX time
     $token = $json['access_token'];
     $endpointurl = $json['download_url'];
     $url_stuff = parse_url($endpointurl);
     $endpoint = $url_stuff['path'];
     $domain = $url_stuff['host'];
     $protocol = $url_stuff['scheme'];
     if(isset($url_stuff['port']))
       $port = $url_stuff['port'];
     else if(strcasecmp($protocol, 'https') == 0)
       $port = 443;
     else
       $port = 80;
     
     # put the array back into an MAC-compatible string
     $imploded = "";
     ksort($data);
     foreach($data as $k=>$v) {
       $imploded .= "$k=" . rawurlencode($v) . "\n";
     }
     $imploded = trim($imploded,"\n");
     $macdigest = "$token\n$timestamp\n$nonce2\n\nPOST\n$domain\n$port\n$endpoint\n$imploded\n";
     $macdigesthash = hash_hmac("sha1", $macdigest, $secretkey, true);
     $signature2 = base64_encode($macdigesthash);
     
     $data['signature'] = $signature2;
     $data['token'] = $token;
     $data['timestamp'] = $timestamp;
     $data['nonce'] = $nonce2;
     
     $db_request = "";
     foreach ($data as $k=>$v) {
       $db_request .= "$k=$v&";
     }
     $db_request = trim($db_request, "&");
     
     $ch = curl_init();
     curl_setopt($ch, CURLOPT_URL, $endpointurl);
    
     curl_setopt($ch, CURLOPT_POST, true);
     curl_setopt($ch, CURLOPT_POSTFIELDS, $db_request);
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     
     $downloaddata = curl_exec($ch);
     curl_close($ch);
    Step 2 is explained in this picture. I have coded based on this and the sample PHP code above.
    Please let me know what I have missed.



    This is my first post to this forum, so kindly excuse me if I have missed any rules.
Working...