title: AWS TranslateText REST API call adding signature v4
body: <p>Actually this is not a question, but an answer for those that are trying to use AWS TranslateText without SDK. I have had many problems until I got a running version.</p>
  
  <p>In my opinion, the AWS documentation for this service is not complete and there are not many examples to check (at least for .Net).</p>
  
  <p>At first, I thought I was not generating the correct V4 signature, but after checking the steps and values once again, I decided to use Postman to call the service. It was very helpful. </p>
  
  <p>Postman can generate the AWS signature! (yeah, I did not know) so finally I noticed the signature value was not the problem.</p>
  
  <p>Checking the request I could see the headers needed and some of its values.</p>
  
  <p>The problem in my case was that I was not sending the "x-amz-target" header. 
  And by chance I found that the value for this header must be "AWSShineFrontendService_20170701.TranslateText"
  (I saw a similar value here <a href="https://rdrr.io/cran/aws.translate/src/R/translateHTTP.R" rel="nofollow noreferrer">https://rdrr.io/cran/aws.translate/src/R/translateHTTP.R</a>)  </p>
  
  <p>This other link was also helpful
   <a href="https://stackoverflow.com/questions/26079050/ivona-request-signing-issue-signature-does-not-match-aws-signature-version-4">Ivona Request Signing Issue - signature does not match (AWS Signature Version 4)</a></p>
  
  <p>So now I have a running version, I want to share my .Net code. I hope it helps :) !!</p>
  
  <pre><code>using Newtonsoft.Json.Linq;
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Net;
  using System.Security.Cryptography;
  using System.Text;
  using System.Web.Script.Serialization;
  
  namespace AWS_TranslateTextTest
  {
      class AWS_TranslateText
      {
  
          // Replace this with your own values
          const string AccessKey = "AKI_ADD_YOUR_ACCESSKEY";
          const string SecretKey = "ADD_YOUR_SECRETKEY";
  
          static void Main()
          {
                  try
              {
                      string text = "Translate this text from English to German.";
                      string sourceLang = "en";
                      string targetLang = "de";
  
                      string responseText = TranslateText(text, sourceLang, targetLang);
  
                      JObject json = JObject.Parse(responseText);
  
                      string translatedText = ""; // to do read response  from json or responseText
  
                      if (json.ToString().Contains("TranslatedText")){
                          //To access to the properties in "dot" notation use a dynamic object
                          dynamic obj = json;
                          translatedText = obj.TranslatedText.Value;
                          Console.WriteLine("TranslatedText is: {0}", translatedText);
                      }
                      else{
                          Console.WriteLine("TranslatedText not found in response.");
                          throw new Exception(json.ToString());
                      }
              }
              catch (WebException ex)
              {
                 Console.WriteLine(ex.Message);
                      if (ex.Response != null){
                  foreach (string header in ex.Response.Headers)
                  {
                      Console.WriteLine("{0}: {1}", header, ex.Response.Headers[header]);
                  }
                  using (var responseStream = ex.Response.GetResponseStream())
                  {
                      if (responseStream != null)
                      {
                          using (var streamReader = new StreamReader(responseStream))
                          {
                              Console.WriteLine(streamReader.ReadToEnd());
                          }
                      }
                  }    }
              }
              catch (Exception ex)
              {
                  Console.WriteLine(ex.Message);
              }           
          }
  
  
            private static string TranslateText(string text, string sourceLang, string targetLang)
          {
              var date = DateTime.UtcNow;
  
              const string algorithm = "AWS4-HMAC-SHA256";
              const string regionName = "eu-west-1";
              const string serviceName = "translate";
              const string method = "POST";
              const string canonicalUri = "/";    
              const string canonicalQueryString = "";  
              const string x_amz_target_header = "AWSShineFrontendService_20170701.TranslateText";
  
                  const string contentType = "application/x-amz-json-1.1";
  
  
              const string host = serviceName + "." + regionName + ".amazonaws.com";
  
              var obj = new
              {
                       SourceLanguageCode = sourceLang,
                       TargetLanguageCode = targetLang,
                       Text = text
              };
              var requestPayload = new JavaScriptSerializer().Serialize(obj);
  
              var hashedRequestPayload = HexEncode(Hash(ToBytes(requestPayload)));
  
              var dateStamp = date.ToString("yyyyMMdd");
              var requestDate = date.ToString("yyyyMMddTHHmmss") + "Z";
              var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, regionName, serviceName);
  
                  var bytes = ToBytes(requestPayload);
  
  
                  var headers = new SortedDictionary&lt;string, string&gt;
              {
  
                       {"content-length", bytes.Length.ToString()},
                       {"content-type", contentType},
                  {"host", host},
                       {"x-amz-date", requestDate},
                       {"x-amz-target", x_amz_target_header}
              };
  
              string canonicalHeaders =
                  string.Join("\n", headers.Select(x =&gt; x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
  
                  string signedHeaders =
                  string.Join(";", headers.Select(x =&gt; x.Key.ToLowerInvariant() ));
  
              // Task 1: Create a Canonical Request For Signature Version 4
              var canonicalRequest = method + '\n' + canonicalUri + '\n' + canonicalQueryString +
                                     '\n' + canonicalHeaders + '\n' + signedHeaders + '\n' + hashedRequestPayload;
  
              var hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));
  
  
              // Task 2: Create a String to Sign for Signature Version 4
              // StringToSign  = Algorithm + '\n' + RequestDate + '\n' + CredentialScope + '\n' + HashedCanonicalRequest
  
              var stringToSign = string.Format("{0}\n{1}\n{2}\n{3}", algorithm, requestDate, credentialScope,
                  hashedCanonicalRequest);
  
  
              // Task 3: Calculate the AWS Signature Version 4
  
              // HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20130913"),"eu-west-1"),"tts"),"aws4_request")
              byte[] signingKey = GetSignatureKey(SecretKey, dateStamp, regionName, serviceName);
  
              // signature = HexEncode(HMAC(derived-signing-key, string-to-sign))
              var signature = HexEncode(HmacSha256(stringToSign, signingKey));
  
  
              // Task 4: Prepare a signed request
              // Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature
  
              var authorization =
                  string.Format("{0} Credential={1}/{2}/{3}/{4}/aws4_request, SignedHeaders={5}, Signature={6}",
                      algorithm, AccessKey, dateStamp, regionName, serviceName, signedHeaders, signature);
  
              // Send the request
                  string endpoint = "https://" + host; // + canonicalUri ;
  
  
              var webRequest = WebRequest.Create(endpoint);
  
              webRequest.Method = method;
              webRequest.Timeout = 20000;
              webRequest.ContentType = contentType;
              webRequest.Headers.Add("X-Amz-Date", requestDate);
              webRequest.Headers.Add("Authorization", authorization);
                  webRequest.Headers.Add("X-Amz-Target", x_amz_target_header);    
  
              webRequest.ContentLength = bytes.Length; 
  
              using (Stream newStream = webRequest.GetRequestStream())
              {
                  newStream.Write(bytes, 0, bytes.Length);
                  newStream.Flush();
              }
  
              var response = (HttpWebResponse)webRequest.GetResponse();
  
              using (Stream responseStream = response.GetResponseStream())
              {
                  if (responseStream != null)
                  {
  
                            using (var streamReader = new StreamReader(responseStream))
                            {
                                  string res = streamReader.ReadToEnd();
                                  return res;
                            }
                  }
              }
  
  
  
              return null;
          }
  
          private static byte[] GetSignatureKey(String key, String dateStamp, String regionName, String serviceName)
          {
              byte[] kDate = HmacSha256(dateStamp, ToBytes("AWS4" + key));
              byte[] kRegion = HmacSha256(regionName, kDate);
              byte[] kService = HmacSha256(serviceName, kRegion);
              return HmacSha256("aws4_request", kService);
          }
  
          private static byte[] ToBytes(string str)
          {
              return Encoding.UTF8.GetBytes(str.ToCharArray());
          }
  
          private static string HexEncode(byte[] bytes)
          {
              return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
          }
  
          private static byte[] Hash(byte[] bytes)
          {
              return SHA256.Create().ComputeHash(bytes);
          }
  
          private static byte[] HmacSha256(String data, byte[] key)
          {
              return new HMACSHA256(key).ComputeHash(ToBytes(data));
          }
      }
  }
  </code></pre>