Forum Discussion
Generating a SAS Token for Azure Blob Storage in C# using APIs
Please refer below on some adjustment and tweak, please make sure fully understanding the codes detail and purpose before apply the change:
private string GenerateSasToken(string accountName, string accountKey, string containerName, string blobName)
{
// Define SAS parameters
string signedPermissions = "r"; // Read permissions
string signedStart = DateTime.UtcNow.AddMinutes(-5).ToString("yyyy-MM-ddTHH:mm:ssZ"); // Start time is 5 minutes ago to account for clock skew
string signedExpiry = DateTime.UtcNow.AddHours(8).ToString("yyyy-MM-ddTHH:mm:ssZ"); // Expiry time 8 hours from now
string signedResource = "b"; // Blob resource type
string signedVersion = "2022-11-02"; // Storage service version
string signedProtocol = "https"; // HTTPS only
string signedIp = ""; // No IP restriction
// Canonicalized resource: "/blob/account/container/blob"
string canonicalizedResource = $"/blob/{accountName}/{containerName}/{blobName}";
// Construct the string-to-sign
string stringToSign = $"{signedPermissions}\n" +
$"{signedStart}\n" +
$"{signedExpiry}\n" +
$"{canonicalizedResource}\n" +
$"\n" + // signedIdentifier (optional, left empty)
$"{signedIp}\n" +
$"{signedProtocol}\n" +
$"{signedVersion}\n";
// Decode the account key from Base64
byte[] keyBytes = Convert.FromBase64String(accountKey);
// Create HMAC-SHA256 hash
using (HMACSHA256 hmac = new HMACSHA256(keyBytes))
{
byte[] signatureBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
string signature = Convert.ToBase64String(signatureBytes);
// Construct the SAS token
var sasToken = HttpUtility.ParseQueryString(string.Empty);
sasToken["sp"] = signedPermissions;
sasToken["st"] = signedStart;
sasToken["se"] = signedExpiry;
sasToken["spr"] = signedProtocol;
sasToken["sv"] = signedVersion;
sasToken["sr"] = signedResource;
sasToken["sig"] = HttpUtility.UrlEncode(signature); // URL-encoded signature
// Return the full blob URL with the SAS token
return $"https://{accountName}.blob.core.windows.net/{containerName}/{blobName}?{sasToken}";
}
}
Hello Kidd_Ip,
I reviewed both functions and didn’t find any noticeable differences between them. However, when I tried using the provided function, I encountered the same error:
<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:e1e86a00-a01e-007a-310a-048187000000 Time:2024-09-11T05:20:23.8063950Z</Message>
<AuthenticationErrorDetail>Signature fields not well formed.</AuthenticationErrorDetail>
</Error>
It seems like the issue might be related to how the signature is being generated or formatted, but I haven't been able to pinpoint the exact cause. Any insights would be greatly appreciated!