In a hackfest this past weekend, I integrated Windows Azure Active Directory (WAAD) into the manufacturing project I'm working on. This is meant as a gentle introduction and is not a comprehensive guide to adding authentication to your application. The application consists of a Windows 8 Store application and a WebAPI backend that interfaces with the rest of the backend systems.

In the early days of .NET, we had to create our own database of users and manage all aspects of getting them logged in. .NET 2.0 introduced ASP.NET membership, which let us offload most of the work. Now, we offload all of the work to WAAD.

What is WAAD?

Active Directory Authentication

WAAD gives us a user directory (and more) and makes it easy to integrate a secure login to your applications with very little work.

Unlike the on-premise version of Active Directory, this is purely for user authentication, not machine authentication (yet).

Active Directory Users List

Long Description:

Enterprise level identity and access management for all your cloud apps. Windows Azure Active Directory is a comprehensive identity and access management cloud solution. You can manage user accounts, synchronize with on-premises directories, get single sign on across Azure, Office 365 and hundreds of popular SaaS applications like Salesforce, Workday, Concur, DocuSign, Google Apps, Box, ServiceNow, Dropbox, and more.

Adding a Login Screen

In our Windows 8.1 application, Login.xaml is the first page we navigate to. The key in this page is that it calls AcquireTokenAsync. This method handles the whole authentication process for us, including bringing up the login dialog:

var authContext = new AuthenticationContext("" + authConfig.DirectoryDomain);
var result = await authContext.AcquireTokenAsync(authConfig.AppRedirectUri, authConfig.AppClientId, new Uri(authConfig.ApiAppSignOnUrl));

Login Screen

Let me repeat this in case it's not sinking in. One line of code has given us an entire functional login dialog!

This is part of the Windows Azure AD Authentication Library for .NET and available through a pre-release NuGet.

(Pro tip: Call TokenCacheStore.Clear() on your AuthenticationContext during WAAD development to clear your cached credentials to force it to authenticate you each time)

Of course AcquireTokenAsync requires parameters that we configured in our WAAD instance. Fortunately we’re using the ConventionConfig library (shameless plug) to store and share our configuration details. This gives us a great centralized location to keep track of the settings we supplied when we configured the directory application.

When the authentication succeeds, we get back a result that has some useful information. First, it contains a bearer token. This is a token that we’ll put in our HTTP calls to prove our identity. We also get a UserInfo object back that contains things like first/last/email.

To make it easy to handle the bearer token, I subclassed the HttpClient like so:

public class SecureHttpClient : HttpClient
    public SecureHttpClient(string bearerToken)
        DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);

Now we can make secure we calls like this:

var secureHttpClient = new SecureHttpClient(app.BearerToken);
var response = await secureHttpClient.GetAsync("http://localhost:3184/api/echo?whoami=true");

If we don’t pass the bearer token, we’ll get a 401 (we'll configure the WebAPI in a moment).

var httpClient = new HttpClient();
var response = await httpClient.GetAsync("http://localhost:3184/api/echo?whoami=true");

If you're using an IoC container, or you don't feel comfortable inheriting from HttpClient, you could also use a factory method to create a configured HttpClient.

In the WebAPI

In the WebAPI project we use OWIN to allow easy injection of middleware. In this case, I’m referencing Microsoft.Owin.Security.ActiveDirectory. In an OWIN startup task, we call the following:

    new WindowsAzureActiveDirectoryBearerAuthenticationOptions
        Audience = config.ApiAppId,
        Tenant = config.DirectoryDomain

Now, it’s just a matter of using the built-in WebAPI authorization functionality. We can put an [Authorize] attribute on a controller or action, or just make everything require authorization by default (probably the best way).

public string Get(bool whoAmI)

In an API action, we can get information about the user through the standard ClaimsPrincipal.Current property.

It’s pretty amazing once you get everything in place.

Valuable Resources I Used