I’ve been quite active on Stack Overflow answering a lot of Azure related questions (mostly around Azure Storage). One thing I noticed there is that there are a lot of folks running into issues when they’re trying to write code themselves for creating Shared Access Signature. Most of the errors they get are around “AuthorizationFailed” error with a variety of error codes.
In this post we’re going to talk about how you can avoid these errors. So let’s start!
Use SDK!
Three words: People, Use SDK!
When you’re trying to hand-craft the Shared Access Signature (SAS), essentially you’re reinventing the wheel and there’s absolutely no need to do so. I mean it, seriously!
Storage team has done an extremely great job of creating SDKs for most commonly used languages including .Net, Java, Node, Python, PHP, and lot more.
Please use them, I implore you :). They are super easy to use and you don’t really have to understand how to create SAS tokens.
Using SDK is a real time saver.
But then, I forget that we as developers derive pleasure by doing things on our own :P. So for those, who still are willing to go ahead and hand craft those SAS tokens, please read along.
So, in my experience answering questions related to various errors on Stack Overflow related to SAS token creations, I observed some common mistakes.
Next, I would like to talk about those and how can we avoid making them.
Read The Documentation!
One thing I really liked about Azure Storage Team is how great job they have done with the documentation. I’m not exaggerating when I say that it is one of best documented sites in Azure.
The team has provided detailed explanation of how you would go about creating SAS token and I would strongly encourage you to read the documentation carefully and follow it to a T.
You can find the documentation here:
Account SAS: https://docs.microsoft.com/en-us/rest/api/storageservices/create-account-sas
Service SAS: https://docs.microsoft.com/en-us/rest/api/storageservices/create-service-sas
Understand Error Message
Whenever you access a SAS URL (say in a browser) and it fails, Azure Storage provides a detailed error message something similar to below:
<?xml version="1.0" encoding="utf-8"?> <Error> <Code> AuthenticationFailed </Code> <Message> Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Time:2020-02-19T13:53:58.2315262Z </Message> <AuthenticationErrorDetail>Signature did not match. String to sign used was r 2020-02-18T00:00:00Z 2020-02-25T00:00:00Z /blob/account/container/blob 2015-04-05 </AuthenticationErrorDetail> </Error>
Please pay special attention to the error message as it contains important details about why the SAS request failed. Use this information to go back and look at your code.
Storage team has also published a list of SAS error codes and I strongly recommend that you take a look at them to find out why your SAS is failing.
You can find this list here: https://docs.microsoft.com/en-us/rest/api/storageservices/sas-error-codes
Base64 Decode Storage Key
Storage account key is a base64 encoded string and in order to compute signature, we have to convert that into byte array. One of the most common mistakes I have seen is that folks treat storage key as a regular string and convert that into byte array using UTF8 or any other encoding.
Assuming you’re using C#, the correct way to get byte array would be:
var storageKeyBytes = Convert.FromBase64String(storageKey);
Pay Special Attention to “StringToSign” formatting
The way you create a SAS Token is that you create a StringToSign
and sign this with your account key to get a signature
. This signature gets included in your SAS URL and Storage Service uses the query parameters in your SAS URL to create it’s own signature
and compares it with the signature you created.
Only when the two values match, SAS request gets processed successfully.
Most of the errors I encountered are related to improperly formatted this StringToSign
. So please special attention to it.
Furthermore, the format of this StringToSign
varies by Storage Service REST API version so please pay special attention to the format of this.
For example, here’s the format if you’re trying to create a SAS Token for a Blob Service resource using REST API version between 2015-04-05
and 2018-03-28
.
StringToSign = signedpermissions + "\n" + //Permissions in SAS e.g. read, write, list etc. signedstart + "\n" + //Date/time in UTC when SAS token becomes effective. signedexpiry + "\n" + //Date/time in UTC when SAS token expires. canonicalizedresource + "\n" + //Canonical resource. signedidentifier + "\n" + //Signed identifier when a SAS token is created using a shared access policy. signedIP + "\n" + //IP address or range from where a SAS URL can be used. signedProtocol + "\n" + //HTTPS or HTTP/HTTPS signedversion + "\n" + //REST API Version rscc + "\n" + //Cache-Control override header rscd + "\n" + //Content-Disposition override header rsce + "\n" + //Content-Encoding override header rscl + "\n" + //Content-Language override header rsct //Content-Type override header
Any slight deviation from this format will result in a Signature did not match
error (an example of it I have included above). Again, please look at the error details to find out the discrepancy.
Also, if you’re not using a parameter in your SAS URL (say cache-control), please make sure to use empty string for that.
Construct Query String Appropriately
Once you have the SAS Token, please make sure that you’re constructing the query string appropriately.
Again, follow the documentation to a “T” to create your SAS Query String.
Don’t Forget To URL Encode Your Query Parameters
It’s important to URL encode your query parameters. This becomes really important for “sig
” query string parameter as it might contain some characters like “/
” and “=
” which if not escaped via URL encoding will result in your SAS URL failure.
Summary
That’s it for this post! I hope you have found this post useful. If you find any issues with the post, please let me know and I will get it fixed ASAP.
Happy Coding!