Francis Ducharme
Francis Ducharme

Reputation: 4987

Uploading to Azure Storage with SAS key directly from client

I'm trying to upload using a SAS key directly from a browser, since files that will be uploaded may be very big (500MB-1GB+) and I don't want them to go through our backend hosted on Azure.

I'm following this great post here but I run into CORS issue on the on hand and a 403 error on the other.

The CORS error

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:36923' is therefore not allowed access. The response had HTTP status code 403.

As you can see I'm trying to get my ASP MVC app running locally to upload to Azure for testing purposes.

And the 403 error received:

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

The way I generated my SAS URI (which expires next year and has Write access) is the following:

// First I create the blob container
public static CloudBlockBlob CreateBlobContainer(string strContainer)
{
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"].ToString());

    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

    CloudBlobContainer container = blobClient.GetContainerReference(strContainer);

    container.CreateIfNotExists();

    CloudBlockBlob blockBlob = new CloudBlockBlob(container.Uri, new StorageCredentials(ConfigurationManager.AppSettings["AccountName"], ConfigurationManager.AppSettings["AccountKey"]));

    return blockBlob;
}

//Then I create a SAS key for that container
public static string GetSaSForBlobContainer(CloudBlockBlob blob, SharedAccessBlobPermissions permission)


    var sas = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
    {
        Permissions = permission,
        SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5),
        SharedAccessExpiryTime = DateTime.UtcNow.AddYears(1),
    });

    return string.Format(CultureInfo.InvariantCulture, "{0}{1}", blob.Uri, sas);
}

//Above methods invoked as such
container = FileManager.CreateBlobContainer("supercontainer");
var sasUri = FileManager.GetSaSForBlobContainer(container, SharedAccessBlobPermissions.Write);

So I create a container then generate a URI that allows uploading to it for a year or so.

The sasUri above ends up being exposed in an ASP MVC view, accessible to javascript logic. It it the baseUrl of the above quoted blog post.

Here's the CORS setting on my container:

CORS

Why would I get this CORS error ? Also, why the error about Authorization header?

I thought the idea of using a SAS URI was to not have to expose an account name/key to the client.

Am I missing something ?

Upvotes: 1

Views: 922

Answers (1)

Gaurav Mantri
Gaurav Mantri

Reputation: 136196

The blog post you linked assumes the shared access signature to be created on blob container and not blob because you don't really know the name of the file user is going to upload beforehand. However in your code you're creating the SAS on blob instead of blob container and this is why you're getting 403 error.

To fix this, please change your CreateBlobContainer method and have it return an object of type CloudBlobContainer instead of CloudBlockBlob. Then, please update your GetSaSForBlobContainer and have its 1st parameter of type CloudBlobContainer instead of CloudBlockBlob. Once you make these changes, you should not get the 403 error you're getting.

Upvotes: 3

Related Questions