ASP.NET Web API Authentication using the Microsoft Account

The last days I’ve been researching some of the new security features in Windows 8. One of the biggest changes in Windows is definitely the fact that you can now login using your Microsoft Account.

I will describe the details how this works in another post, but the net outcome is, that after you logged in using your Microsoft Account, you can access services that are secured using the Microsoft online infrastructure in a single sign-on fashion. And that’s a pretty compelling feature for a number of scenarios.

Windows itself uses the Microsoft backend e.g. to synchronize your Windows and app settings between your various devices. Other built-in apps use Microsoft provided services like Skydrive, contacts or calendar using the same technology.

Of course, you can do the same – e.g. since every Microsoft Account comes with 7 GB of Skydrive storage, you could take advantage of that for document/data roaming. Or you could use the user’s profile to personalize the client app experience.

Another interesting feature is, that you can also integrate your own backend services with Microsoft’s infrastructure to provide the same SSO experience. It’s actually straightforward once you have all the moving parts together ;) Took me a day and a little help from Shelly from the Windows team. Thanks Shelly!

What’ you need to do:

  1. Register your app in the Windows 8 Dev Portal
  2. Configure advanced services
    1. specify a redirect URI
    2. take note of app ID and secret
  3. Install the Live SDK
  4. Create a Windows Store App in Visual Studio
    1. associate your app in Visual Studio with the store app from the portal
  5. Add the client side authentication code

private async void SignInButton_Click(object sender, RoutedEventArgs e)

{

    var scopes = new string[] { “wl.signin”, “wl.basic” };

    var authClient = new LiveAuthClient(_redirectUri);

 

    // try silent logon first

    _loginResult = await authClient.InitializeAsync(scopes);

 

    if (_loginResult.Status != LiveConnectSessionStatus.Connected)

    {

        _loginResult = await authClient.LoginAsync(scopes);

 

        if (_loginResult.Status != LiveConnectSessionStatus.Connected)

        {

            await new MessageDialog(“Access denied!”).ShowAsync();

            return;

        }

    }

 

    await ShowProfile();

}

The first time this code runs, the user needs to allow the app access to his data. From that point this will be a completely silent process.

Depending on the scopes you request, you now have access to various backend services like Skydrive, contacts ect…(see here). You can use the REST API or the Live SDK to access those services, e.g.:

private async Task ShowProfile()
{
    var client = new LiveConnectClient(_loginResult.Session);
    var response = await client.GetAsync("me");
 
    MeImage.Source = new BitmapImage(new Uri(
"https://apis.live.net/v5.0/me/picture?access_token="
+
_loginResult.Session.AccessToken));
 
    foreach (var item in response.Result)
    {
        OutputList.Items.Add(string.Format("{0}: {1}", item.Key, item.Value));
    }
}

 

(Note: an easier way to get to the user profile is to use the UserProfile class in WinRT, but the above code illustrates the concepts)

Another interesting property on the LiveConnectSession is AuthenticationToken. This is a JWT token that you can use to authenticate to your own backend services!

Here’s how it works:

  1. Send the authentication token to your service using whatever means. In Web API world this would typically be header.
  2. On the service side, extract the token.
  3. Call an API at Microsoft to verify the token. The service needs to know the app ID, app secret and redirect URI for that.
  4. The API returns a stable user ID scoped to your app that you can use to associate the app user with your backend data.

Here’s a demo implementation of that (Web API controller):

public string Get()
{
    var authZ = Request.Headers.Authorization;
 
    if (authZ != null)
    {
        var authClient = new LiveAuthClient(
            appId,
            appSecret,
            redirectUri);
 
        return authClient.GetUserId(authZ.Parameter);
    }
 
    return "anonymous";
}

 

Nice!

Obviously, the above code needs to be wrapped in a message handler with proper [Authorize], Thread.CurrentPrincipal and all that jazz ;) But you get the idea.

In Thinktecture.IdentityModel terms that would be:

authentication.AddMicrosoftAccount(
    appId,
    appSecret,

    redirectUri);

Job done ;)

You can btw do more with those tokens, but I’ll leave that for another post. Also make sure you watch Shelly’s talk from //build for more information.

HTH

This entry was posted in ASP.NET, IdentityModel, OAuth, WebAPI. Bookmark the permalink.

8 Responses to ASP.NET Web API Authentication using the Microsoft Account

  1. Vladimir says:

    I wish I ran onto your article before I spent days figuring that out.

    I initially planned to use Azure ACS for user authentication in my app, until I realized that I won’t be having access to user’s email in case of Live identity provider. (I’m using email to identify users of my app.) I ended up using LiveAuthClient/LiveConnectClient with “wl.emails” to authenticate Live accounts, and ACS for Google and Yahoo accounts. That way I get the emails claim in all cases. It feels a bit weird not to use ACS for Live accounts, but I don’t see any alternative.
    As a consequence, now I also have two different token validation implementations on the server side. For ACS tokens I use JWT Token Validation Nuget package (wrapped in a WebApi http handler). For Live tokens I perform the token validation myself (using the application’s secret key, comparing signatures) and I build my own GenericIdentity out of claims.
    Given the description of the architecture, is there a way to simplify/unify token validation on the server side? Are there any alternatives?
    Thanks for any hint/suggestion.

    • Well – first of all you shouldn’t use the email address to identify users, they can be changed.

      The only immutable claim is the name identifier.

      And no – there is no nice way to consolidate the two token validation procedures (that I am aware of).

      • vklisic says:

        I thought of using identity provider + name identifier combo for user identification. However, I think that IPs do not make guarantees that the name identifier will stay invariant forever (even thought in practice this may well be true).
        Regarding the email address — if a user authenticates using a different account than the one used for account creation, he won’t be recognized. But isn’t that true regardless of whether I’m using an email address or a name identifier for identification? They would both appear different.

      • Well – what i am basically saying is, prepare for the case that someone might change his email adress. The nameid + idp combo is supposed to be immutable and unique. But yeah plan for a change here too (from your database schema point of view).

  2. Ishai says:

    I’ve been playing around with that same client side implementation, very easy indeed.

    As far as AddMicrosoftAccount, that’s not in the current IndentityModel, is it?

  3. Pruthvi says:

    Is there a way can we authenticate “ID” value which is coming from live sdk response..??

Leave a comment