I usually access Azure Blob Storage by using a SAS key but I am trying to move everything over to KeyVault and Managed Service Identities (MSI) to improve security and secret management.

During this process I kept on receiving the following error.

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

I could connect to the container using my AAD credentials in Azure Storage Explorer and the time on my local machine was correct which seems to be the main cause of this error but the error was still occurring.

It turned out that this was caused by not providing a Tenant ID to the GetAccessTokenAsync method, when this was used the client authenticated as expected using MSI both in Visual Studio and when running as a Web Job in Azure.

AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();

// Get a credential and create a client object for the blob container.
CloudBlobContainer cloudBlobContainer = new CloudBlobContainer(
	new Uri(context.Configuration["Azure:BlobStorage:ContainerUrl"].ToString()),
	Utilities.GetStorageCredentials(azureServiceTokenProvider, context.Configuration["Azure:BlobStorage:TenantId"].ToString())
	);

public static async Task<TokenCredential> GetTokenCredentialsAsync(AzureServiceTokenProvider azureServiceTokenProvider, string tenantId)
{
	return new TokenCredential(await azureServiceTokenProvider.GetAccessTokenAsync("https://storage.azure.com/", tenantId));
}

public static TokenCredential GetTokenCredentials(AzureServiceTokenProvider azureServiceTokenProvider, string tenantId)
{
	return GetTokenCredentialsAsync(azureServiceTokenProvider, tenantId).Result;
}

public static async Task<StorageCredentials> GetStorageCredentialsAsync(AzureServiceTokenProvider azureServiceTokenProvider, string tenantId)
{
	return new StorageCredentials(await GetTokenCredentialsAsync(azureServiceTokenProvider, tenantId));
}

public static StorageCredentials GetStorageCredentials(AzureServiceTokenProvider azureServiceTokenProvider, string tenantId)
{
	return GetStorageCredentialsAsync(azureServiceTokenProvider, tenantId).Result;
}

As far as I can tell CloudBlobContainer is using v11 of the SDK and v12 uses BlobContainerClient which is the version I should probably be using but MSI authentication doesn’t seem to quite work with this yet as I receive the above error when trying to access, hopefully this will be fixed in future or there will be a more obvious way to set the Tenant ID.


Leave a Reply

Your email address will not be published. Required fields are marked *


Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://dc.services.visualstudio.com/v2/track` resulted in a `400 Invalid instrumentation key` response: {"itemsReceived":1,"itemsAccepted":0,"errors":[{"index":0,"statusCode":400,"message":"Invalid instrumentation key"}]} in D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:113 Stack trace: #0 D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\guzzle\src\Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\promises\src\Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response)) #2 D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\promises\src\Promise.php(156): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\P in D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php on line 113