Unable to use Azure REST Api Shared Key authorization to delete blob - Error 403

Luis 131 Reputation points
2024-03-04T17:57:41.9933333+00:00

Hello everyone, I'm unable to delete a blob from Azure storage account using the REST Api and Shared Key authorization. I can download and upload blobs, but not delete them. I know I'm missing something simple, but I can't point to where the issue is. I used the same method shown in the code below to sign the request for download and upload and it works fine, so it is not the signing code, it should be something on the request header. This is a simplified version of my code:

namespace AzureRestDelete
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string AccountName = "Azure-Account-Name"; 
            string azEndPoint = "blob.core.windows.net"; 
            string AccountKey = "Azure-Storage-Shared-Key"; 

            string ContainerName = "Container-Name"; 
            string ApiVersion = "2023-11-03";
            string sourceBlobName = "Folder1/Folder2/SamplePicture.png";

            string utcDate = DateTime.UtcNow.ToString("R");
            string blobUrl = $"https://{AccountName}.{azEndPoint}/{ContainerName}/{sourceBlobName}";

            using (var request = new HttpRequestMessage(HttpMethod.Delete, blobUrl))
            {
                // Construct the authorization header
               
                string canonicalizedHeaders = $"x-ms-date:{utcDate}\nx-ms-version:{ApiVersion}\nx-ms-delete-snapshots:include"; //nx-ms-lease-id:
                string canonicalizedResource = $"/{AccountName}/{ContainerName}/{sourceBlobName}";
                string stringToSign = $"DELETE\n\n\n\n\n\n\n\n\n\n\n\n{canonicalizedHeaders}\n{canonicalizedResource}";
                string authorizationHeader = SignThis(stringToSign, AccountKey, AccountName);

                //Add headers
                request.Headers.Add("x-ms-date", utcDate);
                request.Headers.Add("x-ms-version", $"{ApiVersion}");
                request.Headers.Add("x-ms-delete-snapshots", "include");
                request.Headers.Add("Authorization", authorizationHeader);

                HttpResponseMessage response = await new HttpClient().SendAsync(request);
                if (response.IsSuccessStatusCode)
                {
                    Console.WriteLine("Blob deleted");
                }
                else
                    Console.WriteLine("Failed:{0}", response.ToString());
            }

            Console.ReadKey();
        }

        private static String SignThis(String StringToSign, 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(StringToSign);
                signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
            }

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

This the request, values have been replaced for security.

{Method: DELETE, RequestUri: 'https://myAzAccount.blob.core.windows.net/containerName/Folder1/Folder2/SamplePicture.png', Version: 1.1, Content: <null>, Headers:
{
  x-ms-date: Mon, 04 Mar 2024 16:57:38 GMT
  x-ms-version: 2023-11-03
  x-ms-delete-snapshots: include
  Authorization: SharedKey AccountName:67890abcdefghijkl1234567890ghjklopqwervhklT=
}}

This is the response:

{StatusCode: 403, ReasonPhrase: 'Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  x-ms-request-id: cdfaca5f-001e-002e-1455-6eb2ae000000
  x-ms-error-code: AuthenticationFailed
  Date: Mon, 04 Mar 2024 16:57:41 GMT
  Server: Microsoft-HTTPAPI/2.0
  Content-Length: 732
  Content-Type: application/xml
}}

I noticed the Content is <null> on the request, according to this there is no need for it, and adding it to the header causes an error. What am I missing? Anyone?

Thank you.

Azure Blob Storage
Azure Blob Storage
An Azure service that stores unstructured data in the cloud as blobs.
2,787 questions
0 comments No comments
{count} votes

Accepted answer
  1. Amrinder Singh 5,155 Reputation points Microsoft Employee
    2024-03-05T08:48:47.94+00:00

    Hi @Luis - Thanks for reaching out.

    From the exception it appears that StringtoSign seem to be not formed correctly. Kindly try printing your StringToSign to verify in case you have missed adding any parameter or some values has not been passed correctly.

    https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key

    1 person found this answer helpful.
    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Anand Prakash Yadav 7,785 Reputation points Microsoft Vendor
    2024-03-05T10:45:26.8366667+00:00

    Hello Luis,

    Thank you for posting your query here!

    The error message indicates that the server failed to authenticate the request, suggesting that there might be an issue with the Authorization header.

    · One of the reasons why this error occurs is you try with the wrong SAS token, or you may give the wrong SAS parameter you have passed in your SAS-URL.

    You may use a tool like Postman to perform the same operation and compare the headers and authorization strings.

    For detailed steps please refer: https://stackoverflow.com/questions/76718804/azurestorage-blob-server-failed-to-authenticate-the-request-error-while-trying

    Reference:

    https://learn.microsoft.com/en-us/rest/api/storageservices/delete-blob?tabs=azure-ad

    · The stringToSign used in creating the Authorization header should be correctly formatted. In some cases, assigning content length as 0 in stringToSign when it should be an empty string can cause a 403 error: Azure Blob Storage - Error trying to delete blob with API REST with C# - Stack Overflow

    · If the blob has an active lease, the x-ms-lease-id header is required. https://learn.microsoft.com/en-us/rest/api/storageservices/delete-blob?tabs=microsoft-entra-id#request-headers

    · Also, please make sure to check if the Clock on your computer is correct.

    Do let us know if you have any further queries. I’m happy to assist you further.

    Please do not forget to "Accept the answer” and “up-vote” wherever the information provided helps you, this can be beneficial to other community members.

    0 comments No comments

  2. Luis 131 Reputation points
    2024-03-05T16:27:54.37+00:00

    The issue was that the canonicalized header were not sorted alphabetically, I had:

    string canonicalizedHeaders = $"x-ms-date:{utcDate}\nx-ms-version:{ApiVersion}\nx-ms-delete-snapshots:include";
    

    when I should have:

    string canonicalizedHeaders = $"x-ms-date:{utcDate}\nx-ms-delete-snapshots:include\nx-ms-version:{ApiVersion}";
    

    Notice second header "x-ms-delete-snapshots" was listed last originally, it should have been after "x-ms-date".

    Thak you All!

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.