0
votes

I am trying to connect to the Azure blob storage API with Node.js. I specifically do not want to use the Blob storage SDK, I want to use axios to hit the REST API. I am just trying to do a simple list containers call as specified here: https://docs.microsoft.com/en-us/rest/api/storageservices/list-containers2. However, I am getting authorization issues.

Here is my simple axios call:

try {
  const azureRes = await axios({
    method: 'GET',
    url:
      'https://<accountname>.blob.core.windows.net/?comp=list',
    headers: {
      'x-ms-version': '2017-11-09',
      Authorization:
        'Bearer <access_token>'
    }
  });
  console.log('azureRes', azureRes);
} catch (err) {
  console.log('err:', err);
}

However I am getting a response with a 403 status code and the error message:

Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

I am authenticating according to https://docs.microsoft.com/en-us/rest/api/storageservices/authorize-with-azure-active-directory, and I am getting my access token from the Azure storage account Access keys tab. Why is my authentication failing?

1
Could you please provide the details of how you get access token?Jim Xu
From the Azure storage account 'Access keys' tab under 'Key'rbuzby
Hi. It is access key and not AD access token. If you want to access storage via AD auth, please refer to my solution.Jim Xu

1 Answers

1
votes

If you want to access Azure blob REST API with Azure AD auth, please refer to the following steps

  1. Assign Storage Blob Data Contributor to AD user or service principal. For more details, please refer to here and here
az role assignment create \
    --role "Storage Blob Data Contributor" \
    --assignee " supported format: object id, user sign-in name, or service principal name." \
    --scope "/subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>"
  1. Get Azure AD token

If you use Service principal, we can get access token with the following API. But please note that if you call the rest API in react application, you will get cors error and we cannot enable cors on Azure AD. So I suggest you call the rest API in back-end application

POST /{tenant}/oauth2/v2.0/token HTTP/1.1          
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

client_id=
&scope=http//storage.azure.com/.default
&client_secret=
&grant_type=client_credentials

If you use Azure AD user, you can integrate Azure AD auth in your react application with package react-aad-msal. Regarding how to configure it, please refer to the sample

  1. Call the API
try {
  const azureRes = await axios({
    method: 'GET',
    url:
      'https://<accountname>.blob.core.windows.net/?comp=list',
    headers: {
      'x-ms-version': '2017-11-09',
      Authorization:
        'Bearer <access_token>'
    }
  });
  console.log('azureRes', azureRes);
} catch (err) {
  console.log('err:', err);
}

Update Regarding how to create sas token, please refer to the following code

  1. install pcakge crypto-js
npm install crypto-js

  1. code
import * as CryptoJS from 'crypto-js';
const accountName =<>;
  const key=<>;
  const start = new Date(new Date().getTime() - (15 * 60 * 1000));
  const end = new Date(new Date().getTime() + (30 * 60 * 1000));
const signedpermissions = 'rwdlac';
  const signedservice = 'b';
  const signedresourcetype = 'sco';
  const signedexpiry = end.toISOString().substring(0, end.toISOString().lastIndexOf('.')) + 'Z';
  const signedProtocol = 'https';
  const signedversion = '2018-03-28';

  const StringToSign =
      accountName+ '\n' +
      signedpermissions + '\n' +
      signedservice + '\n' +
      signedresourcetype + '\n' +
       '\n' +
      signedexpiry + '\n' +
       '\n' +
      signedProtocol + '\n' +
signedversion + '\n';

 var str =CryptoJS.HmacSHA256(StringToSign,CryptoJS.enc.Base64.parse(key));
 var sig = CryptoJS.enc.Base64.stringify(str);
 
 
  const sasToken =`sv=${(signedversion)}&ss=${(signedservice)}&srt=${(signedresourcetype)}&sp=${(signedpermissions)}&se=${encodeURIComponent(signedexpiry)}&spr=${(signedProtocol)}&sig=${encodeURIComponent(sig)}`;

const blobUrl= `<you blob URL>?{sasToken }`