Create SAS Tokens for Azure API Management with an Azure Function

Licensed by CC0 at https://www.pexels.com/photo/colorful-raw-security-key-68174/

Shared Access Signature (SAS) tokens are required to call Azure API Management’s original REST API. We can generate these manually on the Azure portal for testing. However, in production, if you want to invoke the APIM REST APIs programmatically, you’ll need to generate these tokens with a bit of code. There’s a snippet available in the APIM documentation that shows how to do this but it’s (possibly) got a flaw that I’ll address below. Moreover, with Azure Functions available these days, it makes sense to expose this token generator as a service. Here’s the code for an Azure Function to do just that:

using System;   
using System.Net;
using System.Text;   
using System.Globalization;   
using System.Security.Cryptography;

public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
    string id = Environment.GetEnvironmentVariable("APIM_SAS_ID", EnvironmentVariableTarget.Process);
    string key = Environment.GetEnvironmentVariable("APIM_SAS_KEY", EnvironmentVariableTarget.Process);
    DateTime then = DateTime.UtcNow.AddMinutes(10);
    // seconds must be zero for this to work
    DateTime expiry = new DateTime(then.Year, then.Month, then.Day, then.Hour, then.Minute, 0, DateTimeKind.Utc);
    using (HMACSHA512 hmac = new HMACSHA512(Encoding.UTF8.GetBytes(key)))
    {
        string dataToSign = id + "\n" + expiry.ToString("O", CultureInfo.InvariantCulture);
        byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
        string signature = Convert.ToBase64String(hash);
        return req.CreateResponse(HttpStatusCode.OK, new {
            SharedAccessSignature = $"{id}&{expiry:yyyyMMddHHmm}&{signature}"
        });
    }
}

This Azure Function requires two web application settings named APIM_SAS_ID and APIM_SAS_KEY to be used in the hashing process. You can fetch those from the APIM publisher portal (and wherever they may be on the main Azure portal once APIM is fully integrated there). The token that gets generated from this code will be good for ten minutes. You can add more time if you like by modifying the line of code that calls DateTime.AddMinutes(). Currently, APIM SAS tokens can be generated to last up to thirty days although it’s not good practice to make them last that long.

The problem that I found with the snippet of code that was shown in the APIM documentation is that the inclusion of the seconds in the expiration time caused it to fail validation no matter how the middle (EX) portion of the SAS token was formulated. Perhaps I was doing something else wrong but I found that by setting the seconds to zero in the expiration date, I was able to generate SAS tokens that are honored by the APIM REST API. Here’s a GET operation that fetches the value of a property in APIM named SOME_APIM_PROP using the SharedAccessSignature Authorization schema:

GET /properties/?$filter=name eq 'SOME_APIM_PROP'&api-version=2016-10-10 HTTP/1.1
Host: apimftw.management.azure-api.net
Authorization: SharedAccessSignature 57d83b84fe7a801&201703281726&1Zvq5h...
Cache-Control: no-cache

With this Azure Function in place (and the credentials to access it), I can generate SAS tokens for APIM any time I like using a simple, clean HTTP interface. Azure Functions are great architectural building blocks for any modern, API-centric design. If you agree or disagree with that assertion, let me know by reaching me on Twitter @KevinHazzard. Enjoy.

Leave a comment

Your email address will not be published. Required fields are marked *