Search code examples
javascriptazurehttp-status-code-403azure-blob-storageazure-authentication

Azure Blob Storage 403 Authentication Failed Due To Authorization Header


Problem

I have uploaded a set of images (blobs) to a private Azure Blob Storage account, but when I try to access them, I am faced with the following error.


    GET https://<account-name>.blob.core.windows.net/<container-name>/<blob-name> 403 (Server failed 
    to authenticate the request. Make sure the value of Authorization header is formed correctly 
    including the signature.)

I don't have any problems uploading this data as this is done through the server-side using a Django app. I wish to be able to successfully retrieve this uploaded blob data using client-side JavaScript.

Background

I have thoroughly read through and implemented the steps from the Microsoft Azure documentation for authorizing access to my private account via the use of Shared Keys. This includes everything from constructing my signature string to hashing this data using the HMAC SHA-256 algorithm, as detailed in the link above.

I am running everything on Docker containers except for the client-side Vue-based interface which is attempting to invoke the Get Blob API endpoint, as you will see below.

Minimum Reproducible Example

The code that raises this error is as follows:

// Add imports
const crypto = require('crypto');
const axios = require('axios');

// Set Azure blob storage data
const account = "<azure-blob-storage-private-account-name>"
const version = "2020-04-08"
const blob = "<blob-name>"
const container = "<container-name>"
const blob_uri = `https://${account}.blob.core.windows.net/${container}/${blob}`;
const today = new Date().toGMTString();
      
// Construct signature string
const CanonicalisedHeaders = `x-ms-date:${today}\nx-ms-version:${version}\n`;
const CanonicalisedResource = `/${account}/${container}/${blob}`;
const StringToSign = `GET\n\n\n\n\n\n\n\n\n\n\n\n` + CanonicalisedHeaders + CanonicalisedResource;

// Hash string using HMAC Sha-256 and encode to base64
const key = "<shared-access-key-in-base64>";
const utf8encoded = Buffer.from(key, 'base64').toString('utf8');
const signature = crypto.createHmac('sha256', utf8encoded).update(StringToSign).digest("base64");

// Construct the headers and invoke the API call
const blob_config = {
  headers: {
    "Authorization": `SharedKey ${account}:${signature}`,
    "x-ms-date": today,
    "x-ms-version": version
  }
}
await axios.get(blob_uri, blob_config)
  .then((data) => console.log(data))
  .catch((error) => console.log(error.message));

What I have tried

I have tried the following, but none of them have helped me resolve the issue at hand.

  1. Updated CORS settings to avoid CORS-related 403 Forbidden Access issues. CORS Settings
  2. Regenerated my key and connection strings.
  3. Checked the DateTime settings on my local machine and on my Docker containers to ensure they are on the correct GMT time.
  4. Checked that my signature string's components (canonicalized headers, resources, etc.) are constructed according to the rules defined here.
  5. Read through similar StackOverflow and Azure forum posts in search of a solution.

Solution

  • Please try by changing the following lines of code:

    const utf8encoded = Buffer.from(key, 'base64').toString('utf8');
    const signature = crypto.createHmac('sha256', utf8encoded).update(StringToSign).digest("base64");
    

    to

    const keyBuffer = Buffer.from(key, 'base64');
    const signature = crypto.createHmac('sha256', keyBuffer).update(StringToSign).digest("base64");
    

    I don't think you need to convert the key buffer to a UTF8 encoded string.

    Few other things:

    1. Considering you're using it in the browser, there's a massive security risk as you're exposing your storage keys to your users.
    2. Is there a reason you're using REST API directly instead of using Azure Storage Blob SDK?
    3. In browser-based environments, you should be using Shared Access Signature based authorization instead of Shared Access Key based authorization.