Reputation: 1657
Ideally, I would like to access all containers and blobs in storage. The Account SAS token is generated server side in my code. The client will call the API I created in Node.js to receive it. I see that you can create a SAS token manually using Azure Shell, but I prefer to have it generated serve-side since authentication will be implemented.
Following the account SAS generation documentation, it states that the string-to-sign should be constructed like this.
StringToSign = accountname + "\n" +
signedpermissions + "\n" +
signedservice + "\n" +
signedresourcetype + "\n" +
signedstart + "\n" + // optional
signedexpiry + "\n" +
signedIP + "\n" + // optional
signedProtocol + "\n" + // optional
signedversion + "\n"
Example Token from documentation (broken up into multiple lines for better visibility):
sv=2019-02-02&ss=bf&srt=s&st=2019-08-01T22%3A18%3A26Z
&se=2019-08-10T02%3A23%3A26Z&sr=b&sp=rw
&sip=168.1.5.60-168.1.5.70&spr=https
&sig=F%6GRVAZ5Cdj2Pw4tgU7IlSTkWgn7bUkkAg8P6HESXwmf%4B
Token generated from Azure Shell:
se=2019-11-15&sp=rwdlac&sv=2018-03-28&ss=b&srt=sco&sig=<hidden signature>
What is odd is that in the example token, signedversion (sv) is provided first versus signedexpiry (se) in the token from Azure Shell.
Below is the code used to generate the token. I attempted to follow the same order as the token from Azure Shell:
app.get('/sas-token', (req, res, next) => {
// const start = new Date(new Date().getTime() - (15 * 60 * 1000));
const end = new Date(new Date().getTime() + (30 * 60 * 1000));
const signedpermissions = 'rwdlac';
const signedversion = '2018-03-28';
const signedservice = 'b';
const signedresourcetype = 'sco';
// const signedstart = truncateIsoDate(start);
const signedexpiry = truncateIsoDate(end);
// const signedIP = '';
const signedProtocol = 'https';
const StringToSign = STORAGE_ACCOUNT_NAME + "\n" +
signedpermissions + "\n" +
signedservice + "\n" +
signedresourcetype + "\n" +
// signedstart + "\n" +
signedexpiry + "\n" +
// signedIP + "\n" +
signedProtocol + "\n" +
signedversion + "\n"
const key = new Buffer(ACCOUNT_ACCESS_KEY, 'base64');
let sig = crypto.createHmac('sha256', key).update(StringToSign, 'utf8').digest('base64');
let sas =
`se=${signedexpiry}
&sp=${(signedpermissions)}
&sv=${(signedversion)}
&ss=${(signedservice)}
&srt=${(signedresourcetype)}
&sig=${encodeURIComponent(sig)}`;
res.json({
storageUri: STORAGE_ACCOUNT_NAME,
storageAccessToken: sas
});
});
When my client finally makes the request with the generated SAS token, I receive an error:
403 (Server failed to authenticate the request.
Make sure the value of Authorization header is formed correctly including the signature.)
Is it possible to generate an Account SAS token for Blob storage in Node.js?
Upvotes: 4
Views: 5310
Reputation: 23111
According to my research, we can use Azure storage SDK azure-storage
. For more details, please refer to https://github.com/Azure/azure-storage-node/blob/0557d02cd2116046db1a2d7fc61a74aa28c8b557/test/accountsas-tests.js.
var storage = require("azure-storage")
var startDate = new Date();
var expiryDate = new Date();
startDate.setTime(startDate.getTime() - 5*60*1000);
expiryDate.setTime(expiryDate.getTime() + 24*60*60*1000);
var AccountSasConstants = storage.Constants.AccountSasConstants;
var sharedAccessPolicy = {
AccessPolicy: {
Services: AccountSasConstants.Services.BLOB ,
ResourceTypes: AccountSasConstants.Resources.SERVICE +
AccountSasConstants.Resources.CONTAINER +
AccountSasConstants.Resources.OBJECT,
Permissions: AccountSasConstants.Permissions.READ +
AccountSasConstants.Permissions.ADD +
AccountSasConstants.Permissions.CREATE +
AccountSasConstants.Permissions.WRITE +
AccountSasConstants.Permissions.DELETE +
AccountSasConstants.Permissions.LIST,
Protocols: AccountSasConstants.Protocols.HTTPSORHTTP,
Start: startDate,
Expiry: expiryDate
}
};
const accountname ="blobstorage0516";
const key = "";
var sas =storage.generateAccountSharedAccessSignature(accountname,key,sharedAccessPolicy);
console.log(sas);
Besides, if you do not want to use the SDK to generate SAS token, please note that we cannot Omit \n
if we do not use one property in the StringToSign
and the properties we provide in StringToSign
should be used when we create sas token.
For example
const accountname ="blobstorage0516";
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';
let sig = crypto.createHmac('sha256', Buffer.from(key, 'base64')).update(StringToSign, 'utf8').digest('base64');
let sasToken =
`sv=${(signedversion)}&ss=${(signedservice)}&srt=${(signedresourcetype)}&sp=${(signedpermissions)}&se=${encodeURIComponent(signedexpiry)}&spr=${(signedProtocol)}&sig=${encodeURIComponent(sig)}`;
console.log(sasToken)
var storageBlobEndpoint = "https://"+ accountname +".blob.core.windows.net"
var container="blobcontainer";
var blobName="CP4.png";
var requestURL = storageBlobEndpoint + "/" + container + "/" + blobName +"?"+sasToken
console.log(requestURL)
According to my test, we can use the sas token created by above code to do smoe actions on Azure blob storage. For example
Get https://<your account>.blob.core.windows.net/?comp=list+ "&"+"<your sas token>"
Get https://<your account>.blob.core.windows.net/<your container>?restype=container&comp=list +"&" +"<your sas token>"
Besides, regarding how to use the new sdk @azure/storage-blob
to create SAS token, please refer to the following code
const accountname ="blobstorage0516";
const key = "";
const signedpermissions = 'rwdlac';
const signedservice = 'b';
const signedresourcetype = 'sco';
const signedProtocol = 'https';
const signedversion = '2018-03-28';
const cerds = new storage.StorageSharedKeyCredential(accountname,key);
var startDate = new Date();
var expiryDate = new Date();
startDate.setTime(startDate.getTime() - 5*60*1000);
expiryDate.setTime(expiryDate.getTime() + 24*60*60*1000);
expiryDate.setTime(expiryDate.getTime() + 24*60*60*1000);
var result = storage.generateAccountSASQueryParameters({
expiresOn : expiryDate,
permissions: storage.AccountSASPermissions.parse(signedpermissions),
protocol: storage.SASProtocol.Https,
resourceTypes: storage.AccountSASResourceTypes.parse(signedresourcetype).toString(),
services: storage.AccountSASServices.parse(signedservice).toString(),
startsOn: startDate,
version:signedversion
},cerds).toString();
console.log(result);
Upvotes: 8
Reputation: 329
Try with @azure/storage-blob npm package
const sasString = generateAccountSASQueryParameters({ ... }, sharedKeyCredential).toString()
See https://azuresdkdocs.blob.core.windows.net/$web/javascript/azure-storage-blob/12.0.0/globals.html#generateaccountsasqueryparameters
Upvotes: 1