I'm using Ruby to generate a blob URL. e.g.:
The error I get is "Signature did not match":
<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:0daa3721-e01e-0002-3049-58f5bf000000 Time:2023-03-16T20:55:10.7515529Z</Message>
<AuthenticationErrorDetail>Signature did not match. String to sign used was r 2023-03-14T20:52:54Z 2023-03-18T20:52:54Z /blob/anasstoragetest2023/telestream/test.mov https 2021-12-02 b </AuthenticationErrorDetail>
</Error>
Although output of the code shows that the signed string is identical to the one logged in the error message:
String to sign: r 2023-03-14T20:52:54Z 2023-03-18T20:52:54Z /blob/anasstoragetest2023/telestream/test.mov https 2021-12-02 b
I am aware that there is a SAS generator provided by Azure here but it also generates the same error:
blob_path = "/blob/#{account_name}/#{container_name}/#{blob_name}"
signature =
Azure::Storage::Common::Core::Auth::SharedAccessSignature.new(account_name, account_key)
sas_token =
signature.generate_service_sas_token(blob_path, service: 'b', resource: 'b')
puts "\nCreated SAS token: #{sas_token}"
url = "https://#{account_name}.blob.core.windows.net/#{container_name}/#{blob_name}?#{sas_token}"
puts "\nCreated URL: #{url}"
Custom ruby code below. I tried with both ruby 3.1.3 and 2.6.8. Used gem install azure-storage-blob
for both.
Any help would be appreciated!
def generate_blob_url(account_name, account_key, container_name, blob_name)
start_time = Time.now
days = 60*60*24*2
signed_permissions = "r"
signed_start = (start_time - days).utc.iso8601
signed_expiry = (start_time + days).utc.iso8601
canonicalized_resource = "/blob/#{account_name}/#{container_name}/#{blob_name}"
signed_identifier = ""
signed_ip = ""
signed_protocol = "https"
signed_version = "2021-12-02" # "2018-11-09"
signed_resource = "b"
signed_snapshottime = ""
rscc = ""
rscd = ""
rsce = ""
rscl = ""
rsct = ""
string_to_sign = signed_permissions + "\n" +
signed_start + "\n" +
signed_expiry + "\n" +
canonicalized_resource + "\n" +
signed_identifier + "\n" +
signed_ip + "\n" +
signed_protocol + "\n" +
signed_version + "\n" +
signed_resource + "\n" +
signed_snapshottime + "\n" +
rscc + "\n" +
rscd + "\n" +
rsce + "\n" +
rscl + "\n" +
rsct
puts "\nString to sign: #{string_to_sign.gsub("\n", " ")}"
sig = Base64.strict_encode64(OpenSSL::HMAC.digest('sha256', account_key, string_to_sign))
token = "sp=#{signed_permissions}&st=#{signed_start}&se=#{signed_expiry}&spr=#{signed_protocol}&sv=#{signed_version}&sr=#{signed_resource}&sig=#{sig}"
puts "\nGenerated token: #{token}"
url = "https://#{account_name}.blob.core.windows.net/#{container_name}/#{blob_name}?#{CGI.escape(token)}"
end