ADAL for Windows Phone 8.1 – Deep Dive
ADAL for Windows Phone 8.1 is finally here!
With the latest update of the ADAL preview on the NuGet gallery we added a new target platform, Windows Store apps for Windows Phone 8.1. This will allow you to get and store Azure AD tokens from your phone app with the same ease you’ve learned to expect from ADAL on .NET and Windows Store apps; and of course, that means that now calling O365 API, Azure management API or your own API from a phone app becomes a walk in the park
This post will equip you with everything you need to know to get started, and some background on the news the library introduces.
The Basics
Package
ADAL for Windows Phone 8.1 (from now on ADAL for WP8.1 to save me some typing) is packaged together with ADAL .NET and ADAL Windows Store in the Microsoft.IdentityModel.Clients.ActiveDirectory NuGet.
You can add it to your project directly from Visual Studio, by right-clicking->”Manage NuGet Packages…” on the project node in Solution Explorer and searching for “ADAL”. Important: ADAL for WP8.1 is in developer preview, like the other ADAL v2.0 components, hence you can get to it only if you select “Include Prerelease” in the package reference dialog. If you don’t do that, the search will return the ADAL 1.x NuGet which did not support Windows Phone hence won’t be referenceable from your project.
As usual, you can also add the package directly from the Package Manager console via Install-Package:
Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory -Version 2.6.2-alpha -Pre
Note: If you land on this post from the future, please take into account the fact that the version shown here might not be the latest!
Requirements
ADAL for WP8.1 takes advantage of the WebAuthenticationBroker, which is available on the phone only from 8.1 on; hence, ADAL for WP8.1 will only work with Visual Studio 2013 Update 2, with projects targeting Windows Phone 8.1. If you want to use Azure AD or ADFS WS2012R2 on Windows Phone 8 apps, you still need to hit the wire directly at the protocol level.
Furthermore: like its ADAL for Windows Store on Windows 8.x sibling, ADAL for WP8.1 is a Windows Runtime Component. That means that it mandates the Windows Runtime: you will not be able to use ADAL for WP8.1 on Silverlight project types, and if you want to use it in Universal Apps you’ll have to make sure you add ADAL separately on the Windows and Windows Phone projects.
Samples
Together with the release of the updated ADAL NuGet, we published a new sample on GitHub’s AzureADSamples that demonstrates basic intended usage of ADAL for WP8.1.
The sample structure follows the template established by the other native client samples: there is simple a todo service, implemented as a Web API secured by AAD via OWIN middleware, and a simple client that can list and create todo items.
The service project in the new sample solution has been copied verbatim from the .NET and Windows Store samples; the client has been ported to the Windows Phone 8.1 UX paradigm and to the new ADAL for WP8.1 object model.
The readme should have enough info to get you going, however make sure you take a look at the code – it’s heavily commented to ensure that you understand what’s going on. Below you can find a more general discussion on the object model and the why’s behind some of the variations we introduced from the .NET canon. You don’t really need to read it all in order to successfully use the library, but it will provide more context if you plan to stretch the library use beyond the basics.
Programming Model
Like all the other members of the ADAL franchise (the already mentioned .NET and Windows Store; iOS; Android; etc) ADAL for WP8.1 retains the same conceptual model:
- I specify with which authority (AAD tenant or ADFS instance) I want to work with by instantiating a new AuthenticationContext
- I ask for a token for a given resource by calling AcquireToken and specifying the target resource, client coordinates and any extra value my scenario variant requires
- I get back the desired token though an AuthenticationResult instance
- When I need the token again later on, I repeat the exact same AcquireToken call and ADAL will take care of retrieving the token from the cache/refresh the token if it expired but I have a suitable refresh token available/any other token lifecycle paraphernalia I don’t want to know about but I want to reap the benefits of.
Every platform conjugates the above pattern according to the features and programming practices available in their programming stacks; for example, on Objective-C the aforementioned primitives change names to comply with the convention of including the first parameter in the method’s name itself.
When porting ADAL to Windows Phone 8.1, we had to deal with the different way in which the WebAuthenticationBroker (WAB) API are exposed. I went though that in details in this post: I don’t want to force you to read the entire thing, hence I’ll paste the relevant part below.
Referring to the diagram above. The idea is that (1) whenever you call the phone WAB from your code, your app gets suspended and the WAB “app” takes over the foreground spot. The user goes through (2) whatever experience the identity provider serves; once the authentication flow comes to an end, (3) the WAB returns control to your app and disappears.
Here that’s where things get interesting. For your app, this is just another activation: you need to add some logic to detect that this activation was caused by the WAB returning from an authentication, and ensure that the values returned by the WAB are routed to the code that needs to resume the authentication logic and process them.
The idea is that you need in your app an object which implements a well-known interface (IWebAuthenticationContinuable), which includes a method (ContinueWebAuthentication) meant to be used as the re-entry point at reactivation time. In the diagram above it is the page itself that implements IWebAuthenticationContinuable; the OnActivated handler (4) calls the method directly, passing the activation event arguments which will be materialized in ContinueWebAuthentication as WebAuthenticationBrokenContinuationArgs. Those arguments will contain the values you typically expect from the WAB, such as the authorization code produced by an OAuth code grant flow.This is a common pattern in Windows Phone 8.1: it goes under the name “AndContinue”, from the structure of the primitives used. It is applied whenever a “system” operation (such as the WAB, but also file picking) might end up requiring a lot of resources, making it hard for an app on a low power device to keep active in memory both the app and the process handling the requested task. Once again, MSDN provides great coverage for this.
Given that on ADAL relies on the WAB to display the authentication experience when necessary, that presented us with an interesting problem. In the other versions of ADAL, a call to AcquireToken can lead to two different, mutually exclusive outcomes:
- There is a token in the cache that corresponds to the requirements expressed by the parameters passed to the call, or such token can be obtained by other means (refresh token, etc) without showing any UX
- The above does not work out, hence some UX is shown. If the authentication operation succeeds, AcquireToken returns the requested token
The issue we have here is that if you fall in #2, the outcome of AcquireToken is that your app stops whatever it was doing and goes to sleep, only to be woken up in a completely different place. It was clear we had to signal to you that this could happen, hence we had to provide one *AndContinue method of our own; but such method could not cover all of AcquireToken’s capabilities given that in case #1 it does return something and that was in antithesis with the *AndContinue contract. To solve the conundrum, we broke down the traditional AcquireToken function in two different method:
- AcquireTokenSilentlyAsync, which never shows any UX and tries to perform #1 (ADAL for WP8.1 comes with a persistent token cache out of the box, active by default). A successful operation returns a proper AuthenticationResult, while the case in which the requested token cannot be obtained without a prompt results in a null.
- AcquireTokenAndContinue, which always results in a suspension of your app and a roundtrip through the WAB
There’s more, but before going further we need to consider another aspect of the problem.
After a roundtrip through the WAB, the generic Windows Phone continuation model is designed to detect whether your app has been re-activated by the WAB or by any other participant to the continuation system (file picker, etc). That model is not very handy when your app can trigger the out-of-app authentication experience for multiple reasons. In our sample, the main page might need a token (hence trigger an authentication flow) for two operations: getting a list of todo items, or creating a new todo item. Say that while trying to execute one or the other, you get shipped out of app to obtain a token. Once you are back with a token, how do you know what you wanted to do with it in the first place?
The WAB provides a mechanism for maintaining context through calls, which can be used for correlation purposes. However we did not want to burden you further with the need to invent your own correlation system. Instead, we added to AcquireTokeAndContinue the chance for you to specify a delegate (you can think of it as a callback, if that’s more familiar to you) that ADAL will execute once the requested token has been obtained and the execution is back to the current application. Hence, the calling pattern becomes:
AuthenticationResult r = myAC.AcquireTokenSilentlyAsync(…);
if (r!=null)
DoWork(r);
else
AcquireTokenAndContinue(…,DoWork);
In other words:
A. You always try first if you can get a token without showing any UX
B. You organize your app functionality requiring access to protected resources in methods that accept in input an AuthenticationResult
The #B part is what allows the app to maintain a somewhat logical flow, isolating you from the fact that you can occasionally be shipped out-of-app for authentication purposes. Note that the approach is deliciously recursive-prone: in our sample we have a GetTodoList(r) and a PostNewList(r), with the latter including a call to the former to refresh the todo list after having posted the new entry – the top level r is just passed through.
Naturally, for the approach to work you need to ensure that upon re-activation the results obtained from the WAB are handed over to ADAL, which can complete its token acquisition magic (extract the authorization code, hit the token endpoint, cache the results, etc) and dispatch to the delegate you specified at the call origin. This is all obtained by ensuring that upon a WAB re-activation the page calls AuthenticationContext.ContinueAcquireToken(WebAuthenticationBrokerContinuationEventArgs args) – as it is typically done via the IWebAuthenticationContinuable trick explained in the old post on the phone’s WAB and as demonstrated in the sample.
There is one last important variation I need to mention. In the other ADALs, the authority used to initialize an AuthenticationContext is validated upon the first call to AcquireToken. However here there’s no single call – and a failure in validation in the andContinue case would violate the contract (something might still happen before shipping you out of app). Doing the validation in a constructor would be an even worse violation, hence in the case of the phone we moved to a factory pattern for creating AuthenticationContext instances. In ADAL for WP8.1, you create an AuthenticationContext with something like the following:
authContext = AuthenticationContext.CreateAsync(authority).GetResults();
That will ensure that the authority is validated right from the start.
That’s it! As you can see, the programming model retains the same task-oriented approach adopted in all other ADAL flavors, on which you gave very positive feedback. The only variations introduced on the phone version are relatively tame, and I can even see how some appreciate the extra clarity of always knowing with 100% certainty whether a call will result in UX or not – even if it costs a small increase of the moving parts you have to deal with.
Next Steps
Hats off to Kanishk, Boris, Afshin and AnandR who did a fantastic job with ADAL for WP8.1. Support for Windows Phone has been one of the most frequent asks for ADAL, and we are delighted to be finally able to give you something to play with.
The new object model is one of the most important departures form the original primitives yet. We are looking forward to hear from you what do you think about the new approach. We expect this to be a relatively short preview period, hence as soon as you let us know what you think, the higher the probability we’ll be able to include your feedback in the shipping bits.
Happy mobile coding!