Cross-(Modern)-platform Federated Authentication

By | February 23, 2013

So in my previous post we discovered the joys of federated authentication using the sexy tools provided by the Windows Azure team. Now, let’s make the most of them.

Something that is troubling developers more and more as Windows Phone 8 and Windows 8 really stretch their legs in both the consumer and enterprise spaces is how to make the most of their codebases. This rises to the forefront of development very quickly when you see just how similar developing for these two platforms is, from the dev environment, code structure, and available API hooks all the way up to the design and flow of the applications themselves.

Enter Visual Studio 2012’s awesomesauce – the Portable Class Library project type. If you haven’t played with this yet, it really is pretty cool and I highly recommend considering it FIRST when you’re writing a library you intend to reuse. I think most people avoid it because it does what is necessary when it comes to writing code that’s cross-platform: restrict to the lowest common denominator across the platforms you’re targeting. Unfortunately this often takes away things that you wanted to use, but fortunately it assures you that your code – in one library – WILL run on all the platforms you’re targeting. And if you can make it work, it’s a pretty good tool in your back pocket.

To be honest it’s kind of a bummer that I even have to write this post; the Azure team doesn’t appear to know about PCLs. Instead, what they’ve done is created two separate SDKs for Windows Phone 8 and Windows 8 – they are not using a common one to span them both. What this forces us to do is avoid exposing or using those Azure SDKs at the “common” layer of our app. This means we have to abstract it. And in this case it basically means we duplicate/map each of the Windows Phone and Windows 8 versions to a common one in our codebase. If there’s one thing that I hope can come out of this blog post, it’s that Microsoft really needs to start dogfooding their PCL stuff if they want WP and Win8 to start taking over in tandem.

So let’s see how this would apply to Federated login through Azure, and how you can create a quickly-reusable Federated Login library across both Windows Phone 8 and Windows 8.

First step, create a PCL project that targets both Windows Store and Windows Phone 8:

image

image

Note the tidbit at the bottom. Pretty clever, “Yo, we know that you just want these two, but the common parts match up with .Net 4.5 so we’re just going to add that as part of the project settings too” – thanks Microsoft!

Now comes some of the ugly business. This Common library is what we’re going to have our client code reference, so that means we can’t be calling out any of the Azure SDK stuff because those are either specific to Windows Phone, or to Windows 8. So here’s where we roll our own versions of the commonality we want out of each of those. In reality, we’re creating the portable subset of the AMS Authentication portion of the Azure SDKs!

Here’s what my code ended up looking like:

	public enum FederatedLoginProvider
	{
		MicrosoftAccount = 0,
		Google = 1,
		Twitter = 2,
		Facebook = 3,
	}

	public interface IFederatedLogin
	{
		Task DoLoginAsync (FederatedLoginProvider provider);
		Task DoLoginAsync (FederatedLoginProvider provider, string jsonToken);
		Task DoLoginAsync (string authenticationToken);
	}
	public class FederatedLoginUser
	{
		public string UserId { get; set; }
	}

Now then, it’s time to wire in the actual AMS Auth to what we’ve got.

Create a new Windows 8 Class Library to put your Win8 Federated login in to:

image

Add the appropriate references:

image

image

Here’s where it gets a bit dicey. Remember we want to share as much as possible to reduce the amount of code we’re writing and maintaining. With that in mind, let’s create a shared file that we’ll Add as Link to both our Win8 and Windows Phone projects. Here’s what that file looks like:

	public partial class FederatedLogin : IFederatedLogin
	{
		MobileServiceClient _mobileClient;

		#region Constructors
		public FederatedLogin (string azureAppUrl) : this (new Uri (azureAppUrl)) { }
		public FederatedLogin (string azureAppUrl, string applicationKey) : this (new Uri (azureAppUrl), applicationKey) { }
		public FederatedLogin (Uri azureAppUrl)
		{
			_mobileClient = new MobileServiceClient (azureAppUrl);
		}
		public FederatedLogin (Uri azureAppUrl, string applicationKey)
		{
			_mobileClient = new MobileServiceClient (azureAppUrl, applicationKey);
		}
		#endregion

		async public Task DoLoginAsync (FederatedLoginProvider provider)
		{
			MobileServiceAuthenticationProvider azureProvider = (MobileServiceAuthenticationProvider)(int)provider;
			var azureUser = await _mobileClient.LoginAsync (azureProvider);
			return new FederatedLoginUser
			{
				UserId = azureUser.UserId,
			};
		}

		async public Task DoLoginAsync (FederatedLoginProvider provider, string jsonToken)
		{
			MobileServiceAuthenticationProvider azureProvider = (MobileServiceAuthenticationProvider)(int)provider;
			var azureUser = await _mobileClient.LoginAsync (azureProvider, CreateJsonObject(jsonToken));
			return new FederatedLoginUser
			{
				UserId = azureUser.UserId,
			};
		}

		async public Task DoLoginAsync (string authenticationToken)
		{
			var azureUser = await _mobileClient.LoginAsync (authenticationToken);
			return new FederatedLoginUser
			{
				UserId = azureUser.UserId,
			};
		}
	}

A couple of points to note here:

  1. Not all the possible ways of doing Login are supported – there is one that Win8 allows that Windows Phone doesn’t. So we have to scrap it.
  2. The FederatedLoginProvider enumeration maps 1-to-1 to the MobileServiceAuthenticationProvider enumeration exposed by the Azure SDK, but remember we can’t expose it because that would bind us to either Windows Phone or Windows 8.
  3. Our FederatedLoginUser doesn’t have the AuthenticationToken property. This is because the Windows Phone Azure User doesn’t have that property.
  4. Note the ‘public partial’ at the top of this class and the CreateJsonObject() calls within it. This will be important in the next step.

In each SDK, the Json Objects used are different. In Windows Phone they are using Json.Net, while in Windows 8 they are using the Win8 data stack. So that means that instead of passing those Json Objects as parameters as the Azure SDK does in its formal methods, we have to abstract that to a string which we’ll convert to the respective Json object for the platform. Here’s how we do that.

The ‘shared’ file above should be put in a place that isn’t necessarily specific to either platform. I’ve placed it in the same folder as the ‘Common’ library, but it’s not included in the Common library itself.

So before we move on let’s create the Windows Phone 8 class library as well:

image

image

image

Now for both the Win8 and WP8 class libraries, add the shared file as a link:

image

The last step is to implement those Json mappers. In the Windows 8 project, create this:

	public partial class FederatedLogin
	{
		private JsonObject CreateJsonObject (string fromString)
		{
			return JsonObject.Parse (fromString);
		}
	}

and in the Windows Phone one:

	public partial class FederatedLogin
	{
		private JObject CreateJsonObject (string fromString)
		{
			return JObject.Parse (fromString);
		}
	}

therein lies the beauty of partial classes. We just extended one shared class to do two different things in two different projects.

Now the whole solution should build. What you now have is a way to have your common business logic layer perform the necessary login operations required by your application layer by going after our custom-created Interface (IFederatedLogin). In other words, your View (Windows 8 or Windows Phone 8) should register its version of FederatedLogin to a spot in the ViewModel layer that is referencing & using only IFederatedLogin. Now your ViewModel on down is cross-platform between Windows 8 and Windows Phone 8, all thanks to the fancy-dancy PCL. This same pattern is one you can follow throughout your Windows 8 and Windows Phone 8 development.

If you’d like to see the usage at the View layer for these feel free to post a comment and I’ll make that next on the list of .Netitude awesomeness.