tl;dr: I'm trying to connect to an Azure BlobStorage from C# using a SAS, but cannot seem to get past a StorageException
saying the "Server failed to authenticate the request." I suspect something is wrong with my connection string.
I am using libraries Microsoft.Azure.Storage.Blob
11.2.3.0 and Microsoft.Azure.Storage.Common
11.2.3.0 to connect to an Azure BlobStorage from a .NET Core 3.1 application.
My C# code to establish this connection starts as follows:
var storageAccount = CloudStorageAccount.Parse(connectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
When using a connection string that includes the fields AccountName
, AccountKey
, EndpointSuffix
, and DefaultEndpointsProtocol
(this is https
)1, this works flawlessly. (I can connect and do things like enumerate containers and blobs, and also create containers and blobs and upload data.)
Now, I'm supposed to connect to that same BlobStorage with a SAS. For that purpose, I have been given the following bits of information (here anonymized to some kind of "placeholders" because I am going to refer to them in the following):
<StorageAccount>
(same as the value for theAccountName
field in the aforementioned connection string)<Container>
<Blob-SAS-Token>
<Blob-SAS-URL>
(this is actually composed of the other info found here, i.e.<DefaultEndpointsProtocol>://<StorageAccount>.blob.<EndpointSuffix>/<Container>?<Blob-SAS-Token>
)
I can successfully establish a connection to said BlobStorage container from Microsoft Azure Storage Explorer by using the <Blob-SAS-URL>
as described above.2
However, I have so far been unable to successfully use the SAS from my C# code.
I have tried various ways to write my connection string, such as:
BlobEndpoint=<DefaultEndpointsProtocol>://<StorageAccount>.blob.<EndpointSuffix>;SharedAccessSignature=<Blob-SAS-Token>
BlobEndpoint=<DefaultEndpointsProtocol>://<StorageAccount>.blob.<EndpointSuffix>/<Container>;SharedAccessSignature=<Blob-SAS-Token>
According to the docs, this should work. In there, a SAS-based connection string is outlined to contain up to five fields - BlobEndpoint
, QueueEndpoint
, TableEndpoint
, FileEndpoint
, and SharedAccessSignature
- where only (any) one of the four endpoints must be specified beside the SAS.
I have also tried creating/populating the CloudStorageAccount
instance differently than by means of a (possibly misformatted) connection string, such as:
var storageAccount = new CloudStorageAccount(
new StorageCredentials("<Blob-SAS-Token>"),
"<StorageAccount>", "<EndpointSuffix>", true);
Unfortunately, no matter what I try, as soon as I attempt to retrieve any data from the BlobStorage this way, a Microsoft.Azure.Storage.StorageException
is thrown, stating
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
UTC time on my local machine exactly matches current UTC time I can find on online sources. As I can connect with my SAS information from another application on the very same machine, the issue is most probably not related to any aspect of the environment (such as a missing entry for my IP address in some blocking list or similar), anyway. Rather than that, I suspect I am not providing an adequate set of information out of what I have been given for establishing the connection.
What do I have to change to make this connection work?
1: I am going to write this post with some sort of "placeholders" for the various identifiers and credentials so as to not divulge any confidential information. I hope this is not too confusing. On the other hand, it should actually allow for easily adapting the information to whichever sample endpoint is available by a couple of find-and-replace operations.
2: To do so, I right-click the Storage Accounts tree node, then Connect to Azure Storage... > Blob Container > SAS URL (Shared Access Signature