Generate Shared Access Signature

This article shows an Azure API management policy sample that demonstrates how to generate Shared Access Signature using expressions and forward the request to Azure storage with rewrite-uri policy. To set or edit a policy code, follow the steps described in Set or edit a policy. To see other examples, see policy samples.

Policy

Paste the code into the inbound block.

<!-- The policy defined in this file shows how to generate Shared Access Signature (https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1) using expressions. -->
<!-- The snippet forwards the request to Azure storage with rewrite-uri policy. -->

<!-- Copy the following snippet into the inbound section. -->

<policies>
    <inbound>
        <base />
        <!-- Initialize context variables with property values. -->
        <set-variable name="accessKey" value="{{storageAccountAccessKey}}" />
        <set-variable name="storageAccount" value="{{storageAccountName}}" />
        <set-variable name="Content-Type" value="application/json" />
        <set-variable name="resourcePath" value="TableName()" />
        <set-variable name="x-ms-date" value="@(DateTime.UtcNow.ToString("R"))" />

        <!-- Set required headers. -->
        <set-header name="Content-Type" exists-action="override">
            <value>@((string)context.Variables["Content-Type"])</value>
        </set-header>
        <set-header name="Accept" exists-action="override">
            <value>application/json;odata=nometadata</value>
        </set-header>
            <set-header name="Accept-Charset" exists-action="override">
        <value>UTF-8</value>
        </set-header>
            <set-header name="x-ms-date" exists-action="override">
        <value>@((string)context.Variables["x-ms-date"])</value>
            </set-header>
        <set-header name="x-ms-version" exists-action="override">
            <value>2015-04-05</value>
        </set-header>

        <!-- Beginning with version 2009-09-19, the Table service requires that all REST calls include the DataServiceVersion and MaxDataServiceVersion headers. -->
        <!-- See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-the-odata-data-service-version-headers for more information. -->
        <set-header name="MaxDataServiceVersion" exists-action="override">
            <value>3.0</value>
        </set-header>
        <set-header name="DataServiceVersion" exists-action="override">
            <value>1.0;NetFx</value>
        </set-header>

        <set-variable name="CanonicalizedResource" value="@{
            // /{storageAccount}/{resourcePath}
            return string.Format("/{0}/{1}",(string)context.Variables["storageAccount"],(string)context.Variables["resourcePath"]);
            }" />
        
         <set-variable name="StringToSign" value="@{                // https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/authentication-for-the-azure-storage-services
                // {VERB}\n\n\n\n\n{Content-Type}\n\n\n\n\n\n\n{Date}\n{CanonicalizedResource}
                return string.Format(
                "GET\n\n\n\n\n{0}\n\n\n\n\n\n\n{1}\n{2}\n{3}",
                (string)context.Variables["Content-Type"],
                (string)context.Variables["x-ms-date"],
                (string)context.Variables["x-ms-version"],
                (string)context.Variables["CanonicalizedResource"]);
            }" />

        <set-variable name="SharedKey" value="@{
                // https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/authentication-for-the-azure-storage-services
                // Hash-based Message Authentication Code (HMAC) using SHA256 hash
                System.Security.Cryptography.HMACSHA256 hasher = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String((string)context.Variables["accessKey"]));
                return Convert.ToBase64String(hasher.ComputeHash(System.Text.Encoding.UTF8.GetBytes((string)context.Variables["StringToSign"])));
            }" />

        <set-header name="Authorization" exists-action="override">
            <value>@(string.Format("SharedKey {0}:{1}", (string)context.Variables["storageAccount"], (string)context.Variables["SharedKey"]))</value>
        </set-header>

        <!-- Add $filter here: -->
        <rewrite-uri template="/TableName()" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Next steps

Learn more about APIM policies: