Azure SAS (Shared Access Signature) using C#

In this article, I will describe how to generate Azure Shared Access Signature using C#.

In my previous article Azure Shared Access Signature (SAS), I described what is Azure Share Access Signature (SAS) and how to generate SAS token using Azure Portal. SAS token generated from Azure Portal has a predefined start and expiry time. In this sense, I would say that it’s static in nature.

Consider a scenario where you need to generate the SAS token dynamically with each user’s request with a certain set expiration time let’s say 5 min or 5 hours etc., the SAS token created from Azure Portal can’t be used. Here a dynamic SAS token using code (C#) needs to ne generated which I would explain in this article.

The easy way to generate a SAS token from C# code can be found at – https://docs.microsoft.com/en-us/azure/storage/blobs/storage-dotnet-shared-access-signature-part-2

This approach uses the method GetSharedAccessSignature() method of the CloudBlobContainer class or CloudBlobBlob class.

Initially with this implementation, the SAS token worked fine on local machine connected to Azure Storage account (not Azure Storage Emulator). However, after deploying in an Azure Web App, the SAS token didn’t work and gave error – “Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.”

Hence, I came up with the following method for generating a dynamic SAS token. Here I have created a Container SAS token. Blob SAS token can be generated similarly.

Replace the value of storageConnectionString variable’s value with your Azure Storage account’s connection string. You can set the expiryTime variable’s value with your chosen expiry time. You can change the policyIdentifer variable’s value with any name you need for a temporary policy identifier.

private string GetContainerSASToken(string containerName)
{
    string canonicalPathToResource = string.Empty;
    string storageConnectionString = "<your azure storage connection string>";
    string[] tokens = storageConnectionString.Split(';');
    string storageAccountName = tokens[1].Remove(0, 12);
    string permissions = "r";
    DateTime startTime = DateTime.UtcNow;
    DateTime expiryTime = startTime.AddHours(1);
    string policyIdentifer = "tempAccess";
    string signature = string.Empty;

    //Parse the connection string and return a reference to the storage account.
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    //Create the blob client object.
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    //Get a reference to a container to use for the sample code, and create it if it does not exist.
    CloudBlobContainer container = null;

    container = blobClient.GetContainerReference(containerName);
    canonicalPathToResource = ("/" + storageAccountName.Trim() + "/" + containerName).Trim();
    //Get a reference to a blob within the container.
    byte[] keyForSigning = System.Convert.FromBase64String(azureStorageSharedKey.Trim());

    string sStartTime = startTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ");
    string sExpiryTime = expiryTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ");

    string stringtosign = permissions + "n" +
           sStartTime + "n" +
           sExpiryTime + "n" +
           canonicalPathToResource + "n" +
           policyIdentifer;

    using (var hmac = new HMACSHA256(keyForSigning))
    {
        signature = System.Convert.ToBase64String(
           hmac.ComputeHash(Encoding.UTF8.GetBytes(stringtosign))
        );
    }

    BlobContainerPermissions bcPermissions = new BlobContainerPermissions();
    bcPermissions.SharedAccessPolicies.Add(policyIdentifer, new SharedAccessBlobPolicy { });
    container.SetPermissionsAsync(bcPermissions);

    string sharedAccessSignature = string.Format("st={0}&se={1}&sr=c&sp=r&sig={2}&si={3}",
        Uri.EscapeDataString(sStartTime),
        Uri.EscapeDataString(sExpiryTime),
        Uri.EscapeDataString(signature),
        Uri.EscapeDataString(policyIdentifer));

    return string.Format(sharedAccessSignature);
}

Components of the SAS token are as follows:

Description Parameter Value
1 The interval over which the signature is valid
Start time st YYYY-MM-DDThh:mm:ssZ ISO 8061 format
End time se YYYY-MM-DDThh:mm:ssZ ISO 8061 format
2 Resource sr b for blob and c for container
3 Permissions associated with the signature sp read (r),write (w), delete (d), and list (l)
4 The signature sig Base64 encoded string
5 Identifier for policy associated with container si  User defined string eg: –tempAccess

Now we can use this container SAS token access the blobs from the Azure storage container by suffixing the Azure Blob URL with a SAS token prefixed with a ‘?’.

https://<storageaccountname>.blob.core.windows.net/<storagecontainername>/filename.exn?st%3d2018-09-11T13%253A21%253A53Z%26se%3d2018-09-11T14%253A21%253A53Z%26sr%3dc%26sp%3dr%26sig%3doX....................D%26si%3dtempAccess

This concludes the article – Azure SAS (Shared Access Signature) using C#. I hope you liked this article. If you have any comments, questions or suggestions, please post them using the comments section below this article. I will try to respond at my earliest or somebody else reading the article and your comment will try to respond.

Please subscribe to my blog via email to get regular updates on the latest articles and share this article over social networks like Facebook, Twitter etc. You can use the social sharing buttons and social sharing bar provided to share this on social media.

4 thoughts on “Azure SAS (Shared Access Signature) using C#

    1. You need to get the Access Keys from Azure Portal which I have already described in the article with screenshot. I won’t be providing my access keys.

      Like

  1. Your solution resolved the issue for me, too, where using the Microsoft-provided method would work in some environments, but not others.

    Like

  2. Hi Sudipta,

    I am getting the Access Forbidden Error while accessing the storage blob using Rest API. Is there a way you can help me out on this?

    public static string GetStorageSASToken(string storageAccountName,string storageContainerName,string storageSasKey)
    {
    string storagePermission = “rl”;
    string signature = storageSasKey;
    string signedVersionDate = “2018-03-28”;

    string sStartTime = “2019-08-26T04:00:00Z”;// startTime.ToUniversalTime().ToString(“yyyy-MM-ddTHH:mm:ssZ”);
    string sExpiryTime = “2020-08-26T04:00:00Z”;// expiryTime.ToUniversalTime().ToString(“yyyy-MM-ddTHH:mm:ssZ”);

    // Get a reference to a blob within the container.
    byte[] keyForSigning = Encoding.ASCII.GetBytes(storageSasKey);

    var canonicalPathToResource = (“/” + storageAccountName.Trim() + “/” + storageContainerName).Trim();

    string stringToSign = storagePermission + “\n” +
    sStartTime + “\n” +
    sExpiryTime + “\n” +
    canonicalPathToResource + “\n” +

    using (var hmac = new HMACSHA256(keyForSigning))
    {
    signature = System.Convert.ToBase64String(
    hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign))
    );
    }
    string sharedAccessSignature = string.Format(“sv={0}&ss=b&srt=sco&sp={1}&se={2}&st={3}&sr=c&spr=https&sig={4}”,
    signedVersionDate,
    storagePermission,
    sExpiryTime,
    sStartTime,
    signature);

    return string.Format(sharedAccessSignature);
    }

    Please note that If I do not use HMACSHA256 and provide the SAS Key it works as expected.

    Could you please tell me what is it I am missing on this?

    Thanks
    Raj

    Like

Leave a comment