Azure blob storage - upload blob using REST API and shared key authorization header in postman

Azure blob storage - upload blob using REST API and shared key authorization header in postman

In this blog, we will see steps on how to create an authorization header using an Azure storage account shared key and upload a file using Postman. Official documentation for put blob operation is available at the below link-

https://learn.microsoft.com/en-us/rest/api/storageservices/put-blob

  1. Firstly, create four environment variables in Postman as follows-

    Populate the name of storage account in azure_storage_account where you want to upload a file. This storage account name will be used in the request directly.

    Go to your storage account > Access keys and copy any of the key. Populate this key value in variable azure_storage_key-

    Other two variables- header_date and header_authorization will be populated at runtime.

  2. Create a new PUT request "Azure blob storage- upload file" with below url.

    https://{{azure_storage_account}}.blob.core.windows.net/<container_name>/<filePath>

    It will look something like below-

    In this url, {{azure_storage_account}} will read storage account name from environment variable, test is name of my container and newFolder/newFile.txt is my file path where I want to upload my file.

  3. Go to request body tab, select raw, format as text and add some file content that you want to upload.

    If you want to upload a file then instead of raw, select binary and you will be able to browse file and select as body.

  4. Go to request header tab and add below headers. For x-ms-date and Authorization, we are using environment variable values which will be calculated in next step. Content-Length is a mandatory header parameter but Postman will automatically add it, so no need to add explicitly.

  5. Now, go to Pre-request Script tab and add below javascript code to it. This code will run before sending request, calculates and stores x-ms-date and Authorization values.

    Note that this script uses environment variables mentioned above, so make sure those variables are created and populated correctly.

    A detailed explanation about how this Authorization header is calculated can be found with below link-

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

     // Set Date header value for authorization
     // Should be UTC GMT string
     pm.variables.set("header_date", new Date().toUTCString());
     // Get hash of all header-name:value
     const headers = pm.request.getHeaders({ ignoreCase: true, enabled: true });
     // Construct Signature value for Authorization header
     var signatureParts = [
         pm.request.method.toUpperCase(),
         headers["content-encoding"] || "",
         headers["content-language"] || "",
         headers["content-length"]  || "",
     //    pm.request.body ? pm.request.body.toString().length || "" : "",
         headers["content-md5"] || "",
         headers["content-type"] || "",
         headers["x-ms-date"] ? "" : (pm.variables.get("header_date") || ""),
         headers["if-modified-since"] || "",
         headers["if-match"] || "",
         headers["if-none-match"] || "",
         headers["if-unmodified-since"] || "",
         headers["range"] || ""
     ];
    
     // Construct CanonicalizedHeaders
     const canonicalHeaderNames = [];
     Object.keys(headers).forEach(key => {
         if (key.startsWith("x-ms-")) {
             canonicalHeaderNames.push(key);
         }
     });
    
     // Sort headers lexographically by name
     canonicalHeaderNames.sort();
     const canonicalHeaderParts = [];
     canonicalHeaderNames.forEach(key => {
         let value = pm.request.getHeaders({ ignoreCase: true, enabled: true })[key];
         // Populate variables
         value = pm.variables.replaceIn(value);
         // Replace whitespace in value but not if its within quotes
         if (!value.startsWith("\"")) {
             value = value.replace(/\s+/, " ");
         }
         canonicalHeaderParts.push(`${key}:${value}`);
     }); 
     // Add headers to signature
     signatureParts.push.apply(signatureParts, canonicalHeaderParts);
    
     // Construct CanonicalizedResource
     const canonicalResourceParts = [  /${pm.variables.get("azure_storage_account")}${pm.request.url.getPath()}
     ];
     const canonicalQueryNames = [];
     pm.request.url.query.each(query => {
         console.log("query", query);
         canonicalQueryNames.push(query.key.toLowerCase());
     });
     canonicalQueryNames.sort();
     canonicalQueryNames.forEach(queryName => {
         const value = pm.request.url.query.get(queryName); 
         // NOTE: This does not properly explode multiple same query params' values
         // and turn them into comma-separated list
         console.log("queryName", queryName);
         console.log("value", value);
         canonicalResourceParts.push(`${queryName}:${value}`);
     });
     // Add resource to signature
     signatureParts.push.apply(signatureParts, canonicalResourceParts);
     console.log("Signature Parts", signatureParts);
    
     // Now, construct signature raw string
     const signatureRaw = signatureParts.join("\n");
     console.log("Signature String", JSON.stringify(signatureRaw));
    
     // Hash it using HMAC-SHA256 and then encode using base64
     const storageKey = pm.variables.get("azure_storage_key");
     const signatureBytes = CryptoJS.HmacSHA256(signatureRaw, CryptoJS.enc.Base64.parse(storageKey));
     const signatureEncoded = signatureBytes.toString(CryptoJS.enc.Base64);
    
     // Finally, make it available for headers
     pm.variables.set("header_authorization",`SharedKey ${pm.variables.get("azure_storage_account")}:${signatureEncoded}`);
    
  6. Request setup is ready to upload file. Hit send button on request and you will get 201 created response as below. You can go to blob container and verify that newFile.txt is created.

Thanks for reading.

Keep learning!

Did you find this article valuable?

Support Suraj Somani by becoming a sponsor. Any amount is appreciated!