I'm tring to connect to AWS4 Signature method for authentication. (https://orderhive.docs.apiary.io/#introduction/api-requirements/end-point)
My id_token and refresh_token retreive the access_key_id, secret_key, and session_token. But when I try to retreive some information like the warehouse, I receive each time:
"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
The String-to-Sign should have been
'AWS4-HMAC-SHA256 20211217T160055Z 20211217/us-east-1/execute-api/aws4_request 8e3dbc663f97508406c4825b74a647765022ae021fa224754701722b7bcf2288'
And I am using this code like others have done before me in some example.
public const string SCHEME = "AWS4";
public const string ALGORITHM = "HMAC-SHA256";
public const string TERMINATOR = "aws4_request";
public const string ISO8601BasicFormat = "yyyyMMddTHHmmssZ";
public const string DateStringFormat = "yyyyMMdd";
public const string X_Amz_Date = "X-Amz-Date";
public const string RegionName = "us-east-1";
public const string ServiceName = "execute-api";
public const string ContentType = "application/json";
public const string SignedHeaders = "content-type;host;id_token;x-amz-date;x-amz-security-token";
public const string X_Amz_Content_SHA256 = "X-Amz-Content-SHA256";
private Account account;
public void GetWarehouse()
{
try
{
WebRequest webRequest = RequestGet("/setup/warehouse", "", "");
using (WebResponse response = webRequest.GetResponse())
{
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string jsonResponse = responseReader.ReadToEnd();
}
}
catch (Exception ex)
{}
}
public WebRequest RequestGet(string canonicalUri, string canonicalQueriString, string jsonString)
{
string hashedRequestPayload = CreateRequestPayload("");
string authorization = Sign(hashedRequestPayload, "GET", canonicalUri, canonicalQueriString);
string requestDate = DateTime.UtcNow.ToString(ISO8601BasicFormat, CultureInfo.InvariantCulture);
WebRequest webRequest = WebRequest.Create("https://" + Host + canonicalUri);
webRequest.Method = "GET";
webRequest.ContentType = ContentType;
webRequest.Headers.Add("id_token", account.id_token);
webRequest.Headers.Add("X-Amz-Security-Token", account.session_token);
webRequest.Headers.Add(X_Amz_Date, requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add(X_Amz_Content_SHA256, hashedRequestPayload);
return webRequest;
}
private string Sign(string hashedRequestPayload, string requestMethod, string canonicalUri, string canonicalQueryString)
{
var currentDateTime = DateTime.UtcNow;
var accessKey = account.access_key_id;
var secretKey = account.secret_key;
var dateStamp = currentDateTime.ToString(DateStringFormat);
var requestDate = currentDateTime.ToString(ISO8601BasicFormat, CultureInfo.InvariantCulture);
var credentialScope = string.Format("{0}/{1}/{2}/{3}", dateStamp, RegionName, ServiceName, TERMINATOR);
var headers = new SortedDictionary<string, string> {
{ "content-type", ContentType },
{ "host", Host },
{ X_Amz_Date, requestDate.ToString() }
};
string canonicalHeaders = string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
// Task 1: Create a Canonical Request For Signature Version 4
string canonicalRequest = requestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + SignedHeaders + "\n" + hashedRequestPayload;
Console.WriteLine("\nCanonicalRequest:\n{0}", canonicalRequest);
string hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));
// Task 2: Create a String to Sign for Signature Version 4
string stringToSign = SCHEME + "-" + ALGORITHM + "\n" + requestDate + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
Console.WriteLine("\nStringToSign:\n{0}", stringToSign);
// Task 3: Calculate the AWS Signature Version 4
byte[] signingKey = GetSignatureKey(secretKey, dateStamp, RegionName, ServiceName);
string signature = HexEncode(HmacSHA256(stringToSign, signingKey));
Console.WriteLine("\nSignature:\n{0}", signature);
// Task 4: Prepare a signed request
// Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature
string authorization = string.Format("{0} Credential={1}/{2}/{3}/{4}/{5}, SignedHeaders={6}, Signature={7}", SCHEME + "-" + ALGORITHM, accessKey, dateStamp, RegionName, ServiceName, TERMINATOR, SignedHeaders, signature);
Console.WriteLine("\nAuthorization:\n{0}", authorization);
return authorization;
}
private byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName)
{
byte[] kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256(TERMINATOR, kService);
return kSigning;
}
static byte[] HmacSHA256(String data, byte[] key)
{
string algorithm = "HmacSHA256";
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
private static byte[] ToBytes(string str)
{
return Encoding.UTF8.GetBytes(str.ToCharArray());
}
private static byte[] Hash(byte[] bytes)
{
return SHA256.Create().ComputeHash(bytes);
}
private static string HexEncode(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
}
Anyone have any idea what I'm doing wrong? Thank you!