Azure Mobile Service Authentication

It is quickly becoming the case that writing login systems for applications is a superfluous activity; especially when it comes to mobile applications.  Everyone now has Facebook, Twitter, Google or some combination therein.  Being able to leverage these services for authentication is huge because it alleviates the need to maintain separate logins and allows you access to data that the user would otherwise have to re-enter on your site, data is likely going to be as up to date as you may want it to be.

Most services use Open Authentication (OAuth) which allows an application to interact with something like Facebook on the user’s behalf.  Naturally, this comes with many caveats for both sides and thus the protocol is very exacting on what an application must do to be trusted.  I will not spend much time talking about the OAuth spec, I will only say there are at least three values you need to be aware of:

  • Consumer Key – a key value which identifies your app to the given service
  • Consumer Secret – an additional value used in identifying you app to a given service
  • Access Token – a generated key value which symbolizes a relationship between your app, a user, and a service
  • Access Token Secret (optional) – a generated value used in creating a trust relationship between your app, the user, and the service.  This is not always present in the workflow

Luckily, thanks to the popularity of OAuth a number of frameworks have emerged to help abstract the workflow associated with authenticating users.  One such abstraction is the Azure Mobile Services Authentication.

After logging into the Azure Management Portal, find your Mobile Service and select the ‘Identity’ tab.

image

Within this tab you will find space to enter a series of values for each service.  Azure Mobile Service will use these values during the Login operation to obtain the appropriate OAuth values for the user; this allows the user to authenticate with your Mobile Service and make calls to tables that require User Authentication for calls to be executed.

On the device itself, creating this authentication is a simple as this (in C#):

var client = new MobileServiceClient("YOUR MS URL", "YOUR APP KEY");
var user = await client.LoginAsync(providerType);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

In this example, I am defining the client instance at the function level however, I recommend calling using a Singleton to ensure the same MobileServiceClient instance is used each time. The reason for this is you may choose to restrict access to your tables to “User”.  To understand this concept it is important to first think of your tables as REST endpoints.  The permissions you set dictate who can access the endpoint.  In this way you can quickly setup a user driven system without having to write your own login system (just use Facebook, Twitter or another supported platforms).

So, if you will be making calls into other tables using ‘User’ permission a Singleton approach will assist you in ensure the client maintains its authentication. Otherwise you will need to store the UserId and the generated MobileServiceAuthenticationToken for use in subsequent requests.

Why am I telling you about all this?  Well if you are going to carry out operations against Facebook, Twitter, or any other service which uses OAuth for authorization you will need at least an Access Token and in some cases an Access Token Secret (Twitter).  Without this/these value(s) you will not be able to access the respective API to do anything useful.  Unfortunately, the result from Login does not expose these values; this is intentional.

Disclaimer: when dealing with an OAuth system the Access Token (and optional secret value) are EXTREMELY sensitive values which should not be shared with anyone and NEVER transmitted over http (https is fine and is what Mobile Services defaults to).  For this reason, the Azure Mobile Service Login calls does NOT automatically return these values.  However it is possible to get and store them.  Here is an insert trigger that I wrote which saves all user information:

Disclaimer: At the present time the Azure Mobile Service authentication framework does NOT allow the specification of additional Facebook scope values.  This means that using Azure Mobile Services to get the access token will only give you access to the the user’s friend list and their information.  No posting to their wall or anything advanced.  In order to achieve this at present it is necessary to generate the access token outside Mobile Services and then pass that access token to the Azure Mobile Service Authentication framework, described here: http://ntotten.com/2013/03/14/using-windows-azure-mobile-services-with-the-facebook-sdk-for-windows-phone/

function insert(item, user, request) {
     var usersTable = tables.getTable("Users");
     usersTable.where({
          UserId: item.UserId
     }).read({
          success: function(results) {
               // get user identification information
               var identity = user.getIdentities();
                
               // update the item based on the authentication
               if (identity.twitter) {
                    item.AccessToken = identity.twitter.accessToken;
                    item.AccessTokenSeret = identity.twitter.accessTokenSecret;
                }

               if (results == 0) {
                    // insert the new user
                    request.execute();
               }
               else {
                    request.respond(200, item);
               }
          }
    })
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The key here is the call to user.getIdentities().  Mobile Services is tracking the user behind the scenes with all of the appropriate access token and (optional) secret information.  Note: Only Twitter requires the secret, all other providers will have this field empty.

By adding the AccessToken and AccessTokenSecret fields to the item JSON object when request.execute() is called Azure Mobile service will not only store these values for us, it will also create the columns (assuming Dynamic Schema is turned on for at least the first execution).  If the user already exists, we do nothing but respond with the item and status code 200 (Completed).

Either way when this operation completes our Users table will have a row with 5 columns:

  • id – this is a generated column by Azure Mobile Services, it serves as the default primary key
  • UserId – this is a value which is sent back after the Login operation.  An example value might be: “Twitter: 123456”.  I tend to store this value locally on my device and then use it as a look up to get the rest of the information
  • Token – This is the MobileServiceAuthenticationToken which comes down (along with the UserId as the result of the Login operation).  This values is necessary when making User Authenticated Requests to a Mobile Service table
  • Access Token – as shown above this is taken from the result of getIdentities() when called on a non-null user parameter.
    • The user parameter will be non-null when the client is provided with information (UserId and Token) to authenticate the request for the user
  • Access Token Secret – taken from the same, only needed with Twitter

Now, with this information in place we can easily, at startup get the needed information to make our calls to the third party service we are using.

My App

So, understanding how this authentication works let’s look at a quick example.  This first part returns an object representing a user authenticated by Mobile Services.

var client = new MobileServiceClient("APP URL", "APP KEY");

if (providerType == MobileServiceAuthenticationProvider.Facebook)
{
    var fbAuthClient = new FacebookSessionClient(
                 Application.Current.Resources["FacebookAppId"].ToString());
    var authResult = await fbAuthClient.LoginAsync("publish_actions");
    var token = JObject.FromObject(new {access_token = authResult.AccessToken});

    user = await client.LoginAsync(providerType, token);
}
else
{
    user = await client.LoginAsync(providerType);
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

What is happening here is we are requesting an access token from Facebook via the FacebookSessionClient class.  This will handle visual transition as well. Note: my current goal is determine how to use the FacebookClient class entirely to do this, as the session client comes in a different library.

The login method for Mobile Services supports the transmission of a secondary token, which you can use to provide existing login information, if it is not provided Mobile Services will attempt to generate it for you.  For Facebook, if you intend to do more than read the user’s profile information, you do NOT want Mobile Services generating the access token.  Notice the “publish_actions” permission being passed which allows the app to publish to the user’s wall.

The next step is saving the login information to the server (invoking the insert script above).  This is done via the InsertAsync method:

var table = client.GetTable("Users");
await table.InsertAsync(user.AsToken());

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Next, you will want to save the UserId value from the Login locally so it can be used as a lookup key on application start to get the access token.  This will be needed 1) to make authorized calls against the APIs and 2) you will want to check the token is not expired (they dont last forever, 2 months on Facebook).  I decided to make use of Isolated Storage to store my tokens

I will admit that finding out the shortcoming of the Facebook support in Mobile Services was surprising, it does not exist in Twitter.  In my opinion the reason the definition of scope doesnt exist within Azure Mobile Services is simply a timing thing.  And I think it is something that we will see coming down the pipeline in the near future.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s