Posted in:

I blogged a while ago about how you could create a SAS token to provide access to an Azure Storage blob container. In this post, I want to narrow in on the situation where you want to allow someone to simply upload one file to a container. We’ll see how to create the upload SAS token, and how to upload with the Azure SDK and the REST API.

Creating an Upload Shared Access Signature

The first part is pretty standard – we need a connection string for our storage account from which we can get hold of a CloudBlobContainer for the container we want to upload to.

var connectionString = String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
    storageAccountName, // your storage account name
    accessKey); // your storage account access key
var storageAccount = CloudStorageAccount.Parse(connectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("my-container");

Next we need to specify the SharedAccessBlobPolicy. We want to be able to Create a file and Write to it, and we also need to reserve a reasonable window of time for the file to be uploaded in.

SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(30);
sasConstraints.Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Create;

var blob = container.GetBlockBlobReference("outputfile.txt");
Console.WriteLine("{0}{1}",
    blob.Uri, blob.GetSharedAccessSignature(sasConstraints));

We then get a blob reference to the filename we want to be able to write to (this file doesn’t need to exist in the container), and then we can use GetSharedAccessSignature in combination with the blob’s Uri to get the full Uri and query string we need to be able to upload.

This results in a SAS Uri looking something like this:

https://mystorageacct.blob.core.windows.net/my-container/outputfile.txt?sv=2015-12-11&sr=b&sig=9UZXdW5eqoN7aiKqvnUo60gBAr1Y2feVNnIn2Hh2iU4%3D&se=2017-02-05T12%3A52%3A34Z&sp=cw

Uploading the Blob

So if we have this Shared Access Signature, how do we actually upload to it? Well, very simply with the Azure SDK. We just need to pass the full SAS Uri into a CloudBlockBlob and then we can use various methods such as UploadFromFile, UploadFromStream or UploadFromByteArray to write to it.

var sas = "https://mystorageacct.blob.core.windows.net/..."; 
var cloudBlockBlob = new CloudBlockBlob(new Uri(sas));
await cloudBlockBlob.UploadFromFileAsync(@"c:\myfile.txt");

Note that the name of the file cannot be changed from what is specified in the SAS Uri, so the caller is only able to write to this one file in your container.

If you prefer, you can use the Azure Blob storage REST API to upload the content directly:

var client = new HttpClient();
var content = new StringContent("Some content");
content.Headers.Add("x-ms-blob-type", "BlockBlob");
var response = await client.PutAsync(sas, content);
response.EnsureSuccessStatusCode();

Comments

Comment by gopal krishna Banbhatta

Hi,
I am getting the error below when trying to upload a text file using a javascript library -
<error>
AuthorizationPermissionMismatch
<message>
This request is not authorized to perform this operation using this permission. RequestId:xxxxxx Time:2019-10-30T10:13:09.5858632Z
</message>
</error>

I thought of giving my container public Add | Create access, but the only place I could see this option is on the policy level which you have not used here in this example. So, is there a way I can use the existing policy to create the SAS token or giving write access at the container level.
Thanks

gopal krishna Banbhatta
Comment by Mark Heath

try including Read access - there are some scenarios in which this is needed for uploads

Mark Heath
Comment by Kriti Pandey

Hi Mark,
I am trying to upload 800MB file using :
requests.put(sas_uri, data = open(file, 'rb')
but it is failing with - Connection aborted, OS32, EPIPE error. It has to do with the size of the file. Is there a way to upload this file?

Kriti Pandey
Comment by astrominion

hello, i have same problem with you. my solution is split file (you can find thousand there), upload partially, and then merge parted file by committing list of chunk`s name.
Reference: https://docs.microsoft.com/...

astrominion
Comment by Robert Sandona

Thanks for sharing this information. Really appreciated!

Robert Sandona
Comment by Askar Ibragimov

It is sad that you do not provide import/npm install statements for dependences here.

Askar Ibragimov
Comment by Mark Heath

this is C#, not node

Mark Heath
Comment by Askar Ibragimov

sorry. my bad.

Askar Ibragimov
Comment by murali

Thank you so much for this article, it help me lot.

murali
Comment by xf6jx5fq

Just wondering if using SAS should be banned all the way since the signature is embedded in the url. I failed to see how this can be secure.

xf6jx5fq
Comment by Fabian Schmied

Can you limit the maximum upload size with this approach? How do you avoid people DoS-ing you with huge files?

Fabian Schmied
Comment by Md. Masum Billah

Thanks a lot. It helps me a lot

Md. Masum Billah