Error 403 when trying to update entity in azure table storage using HttpClient

316 Views Asked by At

enter image description hereError Code - 403 "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature."

It is not authenticating the request but I have added almost all the authentication headers

resourcePath = TableName

If someone could help me to solve the issue

public async Task<string> UpdateEntityAsync(string department, string id, EmployeeDetails employee)
        {
                string uri = @"https://" + storageAccount + ".table.core.windows.net/" + resourcePath + "(PartitionKey='" + department + "',RowKey='" + id + "')";
                string body = JsonConvert.SerializeObject(employee);
                //body = string.Format(body, Guid.NewGuid());

                var request = _httpClientFactory.CreateClient();
                string formatedTime = DateTime.UtcNow.ToString("R");
                request.DefaultRequestHeaders.Add("x-ms-date", formatedTime);

                if (request.DefaultRequestHeaders.Contains("x-ms-version"))
                    request.DefaultRequestHeaders.Remove("x-ms-version");

                request.DefaultRequestHeaders.Add("x-ms-version", "2015-12-11");

                if (request.DefaultRequestHeaders.Contains("DataServiceVersion"))
                    request.DefaultRequestHeaders.Remove("DataServiceVersion");
                request.DefaultRequestHeaders.Add("DataServiceVersion", "3.0;NetFx");

                if (request.DefaultRequestHeaders.Contains("MaxDataServiceVersion"))
                    request.DefaultRequestHeaders.Remove("MaxDataServiceVersion");
                request.DefaultRequestHeaders.Add("MaxDataServiceVersion", "3.0;NetFx");

                if (request.DefaultRequestHeaders.Contains("If-Match"))
                    request.DefaultRequestHeaders.Remove("If-Match");
                request.DefaultRequestHeaders.Add("If-Match", "*");

                request.DefaultRequestHeaders.Accept.Clear();
                request.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                //Adding the Authorization header to the request
                string authorization = GetSignedStringPut("PUT", formatedTime, resourcePath, storageAccount, accessKey, department, id);
                request.DefaultRequestHeaders.Add("Authorization", authorization);

                request.DefaultRequestHeaders.TryAddWithoutValidation("Content-Length", body.Length.ToString());
                var stringContent = new StringContent(body);
                stringContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                HttpResponseMessage messageResult = await request.PutAsync(uri, stringContent);
                if (messageResult.IsSuccessStatusCode)
                {
                    return messageResult.ToString();
                }
                else
                {
                    return "null";
                }
            }

            public static string GetSignedStringPut(string httpMethod, string time, string urlPath, string account, string key, string department, string id)
            {
                String contentMD5 = String.Empty;
                String contentType = "application/json";
                String canonicalizedResource = String.Format("/{0}/{1}", account, urlPath) + "(partitionkey='" + department + "',rowkey='" + id + "')";
                //stringToSign format for SharedKey
                String stringToSign = String.Format(
                      "{0}\n{1}\n{2}\n{3}\n{4}",
                      httpMethod,
                      contentMD5,
                      contentType,
                      time,
                      canonicalizedResource);
                //stringToSign format for SharedKeyLite
                //stringToSign = String.Format("{0}\n{1}", time, canonicalizedResource);
                string signedKey = SignThisPut(stringToSign, key, account);
                return signedKey;
            }

            private static String SignThisPut(String canonicalizedString, string Key, string Account)
            {
                String signature = string.Empty;
                byte[] unicodeKey = Convert.FromBase64String(Key)
    ;
                using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
                {
                    Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
                    signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
                }

                String authorizationHeader = String.Format(
                      CultureInfo.InvariantCulture,
                      "{0} {1}:{2}",
                      "SharedKey",
                      Account,
                      signature);

                return authorizationHeader;
            }
        }
}

1

There are 1 best solutions below

6
Gaurav Mantri On

I believe the issue is coming because you are using REST API version 2015-12-11 which does not support XML payload. From the documentation here:

JSON is the recommended payload format, and is the only format supported for versions 2015-12-11 and later.

Please change the request body to JSON and content type to application/json and you should not get the error.