Check for expired Azure Mobile Services authentication tokens


When Microsoft Azure Mobile Services was first released, we only had basic guidance for authentication—basically just how to use the LoginAsync function. One of our customers had an app (let’s call it a “current events” app) that required authentication, and they were having trouble when an event occurred and lots of users would hit the service attempting to login—you can see the problem there. After that, we added the strong recommendation and guidance for caching the authentication token (for both the Mobile Services token and any other client-side tokens generated by Microsoft account, Facebook, etc.) and trying to use it before requesting a brand new token from the service using LoginAsync.

Limitations of our token caching guidance

I was relatively happy with this guidance except for one thing…the cached token could be expired (depending on how long ago authentication occurred). The code included a quick query to ping the service and test the token for expiration. This always seemed lame to me for two reasons: 1) the token could expire at any time—even mid-request so 401s should really be handed in the request pipeline (as in Carlos’ blog post), and 2) this is an extra request to the service that is really useless as it doesn’t tell us anything. One of the devs on the team had suggested back when to just check the expiration time in the token itself, but no one had this code available and I never got around to it.

Recently, a customer asked via Disqus why we don’t have a helper method in the client that checks for expired tokens. This is actually a great suggestion (remember to request new features here). (Another good question is why the client library doesn’t automatically retry LoginAsync when a 401 is returned with a non-null MobileServicesUser—but that’s another discussion.) It was finally time to figure this token expiration date thing out.

First of all, here is a Mobile Services token:

image

OK, that is an unintelligible mess. How do I find the expiration date in there?

Deciphering the Mobile Services authentication token

The Rosetta stone for the Mobile Services authentication token is provided in one of Josh Twist’s old blog posts, part of his seminal The twelve days of ZUMO series: Generating your own ZUMO auth token (Day 8). In this post, Josh shows how a valid token is constructed (using JavaScript in Node.js). This means to decode the token I just needed to reverse the steps he used to generate it.  Here is where Josh puts the pieces together:

var s2 = JSON.stringify(j2);
var b1 = urlFriendly(base64(s1));
var b2 = urlFriendly(base64(s2));
var b3 = signature(b1 + "." + b2);
return [b1,b2,b3].join(".");

Looking closely at the raw token string, I noticed the period delimiters. It turns out a Mobile Services token conforms to the JSON Web Token (JWT) draft, and is a concatenation of a JSON Object Signing and Encryption (JOSE) header, a JWT claims set, and a signature over the two. The first two parts are converted to base64, made URL friendly, signed, and the whole thing is concatenated. This means that I only needed to look at the second part, decode it to a regular JSON string and get the expiration part. The following code decodes the JWT claims:

// Get just the JWT part of the token.
var jwt = client.CurrentUser
    .MobileServiceAuthenticationToken
    .Split(new Char[] { '.' })[1];

// Undo the URL encoding.
jwt = jwt.Replace('-', '+'); 
jwt = jwt.Replace('_', '/'); 
switch (jwt.Length % 4) 
{
    case 0: break; 
    case 2: jwt += "=="; break; 
    case 3: jwt += "="; break; 
    default: throw new System.Exception(
        "The base64url string is not valid.");
}

// Decode the bytes from base64 and write to a JSON string.
var bytes = Convert.FromBase64String(jwt); 
string jsonString = UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length);

Now, the JWT is clearly readable:

image

Extracting the expiration date

We want to get the exp field, which it turns out (from a little trial and error) represents the number of seconds since Jan 1, 1970 UTC (even though Josh was using milliseconds in his example). Here’s the code that makes the conversion using LINQ to JSON:

// Parse as JSON object and get the exp field value, 
// which is the expiration date as a JavaScript primative date.
JObject jsonObj = JObject.Parse(jsonString);
var exp = Convert.ToDouble(jsonObj["exp"].ToString());

// Calculate the expiration by adding the exp value (in seconds) to the 
// base date of 1/1/1970.
DateTime minTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var expire = minTime.AddSeconds(exp);

Creating the extension method

All that was left to do was to wrap the whole thing in a nice convenient extension method for MobileServicesClient:

public static class TokenExtension
{
    /// <summary>
    /// Returns true when the authentication token for the current user is expired.
    /// </summary>
    /// <param name="client">The current MobileServiceClient instance</param>
    /// <returns>true when the token is expired; otherwise false.</returns>
    public static bool IsTokenExpired(this IMobileServiceClient client)
    {

        ...

        // If the expiration date is less than now, the token is expired and we return true.
        return expire < DateTime.UtcNow ? true : false;
    }
}

I have attached the entire class file for the extension method for download in this blog post. As soon as I wrote this, I envisioned other cool method overloads, like including an expiration buffer. You could also automatically login from this method, since the JWT declares the authentication provider (in the aud field). At least, that is something to get folks going in the right direction.

Don’t forget that this week is the //build conference!

Cheers!

Glenn Gailey

TokenExtension.cs

Comments (2)

  1. Tyler says:

    If I´m trying it with an UWP-App the token is always expired.

  2. Iamnvincible says:

    this line:
    return expire < DateTime.UtcNow ? true : false;
    should replace '’

Skip to main content