I'm using Azure functions to generate a SAS Token for Container level. Here is the code:
const {
StorageSharedKeyCredential,
ContainerSASPermissions,
SASProtocol,
generateBlobSASQueryParameters,
} = require('@azure/storage-blob');
require('dotenv').config();
const {STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_KEY1} = process.env;
const constants = {
accountName: STORAGE_ACCOUNT_NAME,
accountKey: STORAGE_ACCOUNT_KEY1
};
const sharedKeyCredential = new StorageSharedKeyCredential(
constants.accountName,
constants.accountKey
);
async function createContainerSas(containerName) {
const sasOptions = {
containerName,
permissions: ContainerSASPermissions.parse("racwli"),
startsOn: new Date(),
expiresOn: new Date(new Date().valueOf() + 86400000),
protocol: SASProtocol.Https,
};
const sasToken = generateBlobSASQueryParameters(sasOptions, sharedKeyCredential).toString();
return sasToken;
}
module.exports = async function (context, req) {
const sasToken = await createContainerSas(req.query.containerName);
context.res = {
body: {
sasToken
}
};
};
I'm runing locally as http://localhost:7071/api/blobstorage-controller/{CONTAINER_NAME}?comp=list&restype=container&{GENERATED_SAS_TOKEN}
and a deployed version.
When running the URL above I'm getting the following error:
<?xml version="1.0" encoding="utf-8"?> <Error> <Code>AuthenticationFailed</Code> <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:0986c9be-d01e-000b-37ba-27627d000000 Time:2023-12-05T20:34:10.2329768Z</Message> <AuthenticationErrorDetail>Signature fields not well formed.</AuthenticationErrorDetail> </Error>
I followed every doc on Azure and was not able to make this work!
NOTE: Using a token genereted on Azure Portal works! But I'm expecting to get it working with only a SASToken.
[Edited]Alternative Solution
I came across this doc using ConnectionString: Exercise - Build your serverless backend
const {
StorageSharedKeyCredential,
ContainerSASPermissions,
generateBlobSASQueryParameters
} = require("@azure/storage-blob");
require('dotenv').config()
const { extractConnectionStringParts } = require('./utils.js');
const {STORAGE_CONNECTION_STRING}= process.env;
module.exports = async function (context, req) {
const reqPermissions = (req.query.permissions || req.body.permissions || 'rwl').split('');
const permissionsOrder = ["r", "a", "c", "w", "d", "x", "y", "l", "t", "m", "e", "o", "p"];
const permissions = reqPermissions.sort((a, b) => {
return (
permissionsOrder.indexOf(a) - permissionsOrder.indexOf(b)
);
}).join('');
console.log(permissions);
const container = req.query.containerName || req.body.containerName;
context.res = {
body: generateSasToken(STORAGE_CONNECTION_STRING, container, permissions)
};
};
function generateSasToken(connectionString, container, permissions) {
const { accountKey, accountName } = extractConnectionStringParts(connectionString);
const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey.toString('base64'));
let expiryDate = new Date();
expiryDate.setHours(expiryDate.getHours() + 24);
const sasToken = generateBlobSASQueryParameters({
containerName: container,
permissions: ContainerSASPermissions.parse(permissions),
expiresOn: expiryDate,
}, sharedKeyCredential);
return {
sasToken: sasToken.toString(),
};
}
While I have no better way to do that, this alternative solution worked for me.
When you are trying to access Azure blob container
you need to use https://storageaccount.blob.core.windows.net/containername?restype=container&comp=list
if you are trying to access Emulated Storage container use http://127.0.0.1:10000/devstoreaccount1/mycontainer?restype=container&comp=list
For reference check this document.
This code worked for me.
const {
StorageSharedKeyCredential,
ContainerSASPermissions,
SASProtocol,
generateBlobSASQueryParameters,
} = require('@azure/storage-blob');
require('dotenv').config();
const { STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_KEY1 } = process.env;
const constants = {
accountName: STORAGE_ACCOUNT_NAME,
accountKey: STORAGE_ACCOUNT_KEY1,
};
const sharedKeyCredential = new StorageSharedKeyCredential(
constants.accountName,
constants.accountKey
);
async function createContainerSas(containerName) {
try{
const sasOptions = {
containerName,
permissions: ContainerSASPermissions.parse("racdl"),
protocol: SASProtocol.HttpsAndHttp,
startsOn: new Date(),
expiresOn: new Date(new Date().valueOf()+86400000),
};
const sasToken = generateBlobSASQueryParameters(
sasOptions,
sharedKeyCredential
).toString();
return sasToken;
}
catch (error){
console.error("error: ", error);
throw error;
}
}
module.exports = async function (context, req) {
try{
const containerName = req.query.containerName;
const sasToken = await createContainerSas(containerName);
console.info("container: ",containerName);
const urlWithSasToken = `https://nodejsstoragecontainer.blob.core.windows.net/${containerName}?restype=container&comp=list&${sasToken}`;
context.res = {
body: {
containerName,
sasToken,
urlWithSasToken,
},
};
}
catch (Error) {
console.error("error: ",Error);
}
};
OUTPUT: