Tuesday, June 4, 2013

Single Sign On with OAuth in Windows Store Apps

Various providers often provide documentation and even SDKs that make it easier to connect with and authenticate to their service. The problem is that most scenarios assume a web-based application or specific mobile clients. The process in general looks something like this:

oauth

How can you take protocol modeled for the web and make it work in an app that is running on a Windows 8 device? The answer is the WebAuthenticationBroker component in the Windows Runtime.

The web authentication broker is designed to assist you with single sign-on scenarios by emulating a fully web-based experienced. You provide the broker with a starting URL. This URL typically contains information such as special application codes and passwords used to verify your app’s identity with the provider and a redirect URL the provider should send the user to when they are authenticated. You also provide the broker with an ending URL. This is where the magic happens for the broker.

The broker starts by popping up a dialog that is essentially a web browser window without chrome. The user will be presented with the provider’s login page, such as the Facebook example shown here.

facebooksso

The user can then enter their credentials and authorize the app to information. Once they are finished, the provider will redirect them to a final URL. The web broker is configured to listen for this URL, and instead of serving the page, it will intercept the request and provide the details to your app. You can then parse the content of the redirect to obtain the access token that validates the user’s identity and can be used to make further requests from the provider.

The logic to authenticate with Facebook and receive a token is fairly straightforward. There are two URLs involved. The first is the URL used to authenticate with Facebook that we’ll call FaceBookAuth. The URL must be passed a client id (your app id), a redirect URL to send the user to when they are authenticated, a scope to determine what information you will be requesting, and the type of response (we want a token).

The second URL is the redirect URL. Because the example is a client app and not a web page, Facebook’s own confirmation URL is used as the redirect URL and stored in the FacebookRedirectUri constant. After the user authenticates, they will be redirected to the Facebook page. The web authentication broker will be listening for the redirect and will intercept it. The scope informs Facebook what you intend to access, for example, an email.

private const string FaceBookAuth =
https://www.facebook.com/dialog/oauth?client_id={0}&redirect_uri={1}&scope={2}&response_type=token;
private const string FacebookRedirectUri = "https://www.facebook.com/connect/login_success.html";

The code builds the start and end URLs and then calls the AuthenticateAsync method on WebAuthenticationBroker in the Windows.Security.Authentication.Web namespace. It is passed a set of options, the URL to start with, and the URL to listen to.

WebAuthenticationResult result = await WebAuthenticationBroker.AuthenticateAsync(

                                        WebAuthenticationOptions.None,
                                        startUri,
                                        endUri);

The authentication options are provided by passing flags specified in the WebAuthenticationOptions enumeration. Possible values include:

  • None – no options.
  • SilentMode – used for pure SSO that has no UI involved. If the provider displays a web page the authentication will fail.
  • UseTitle – instructs the web authentication broker to parse the title of the window for the web page and return it in the ResponseData property to allow you to parse it as needed.
  • UseHttpPost – when the provider performs a POST to the final website, this option will provide the contents of the POST in the ResponseData property.
  • UseCorporateNetwork – this will render the web page in a special container that supports enterprise authentication and private networks for intranet authentication and requires that similar capabilities are declared for the app.

The result will return a response status (successful, an HTTP error, or the user canceled) and the contents of the final redirect. The Facebook redirect uses a hash to separate the URL from a set of response parameters send in a query string format (name/value pairs). The first parameter is the token you can use for further access, and the second is when the token will expire. Use this to store the token and reuse it without having to request a new one each time.

if (result.ResponseStatus == WebAuthenticationStatus.Success)

{
    var data = result.ResponseData.Substring(result.ResponseData.IndexOf('#'));
    var values = data.Split('&');
    var token = values[0].Split('=')[1];
    var expirationSeconds = values[1].Split('=')[1];
    var expiration = DateTime.UtcNow.AddSeconds(int.Parse(expirationSeconds));
    this.dataStorage.Save(this.Name, expiration, token);
    return token;
}

Once the token has been received, the main authentication step is complete. Now you can use the token to request information about the user. For example, you can obtain their preferred email address to default it without asking or to identify the user internally to your app.

private const string FacebookIdentityUrl = "https://graph.facebook.com/me?scope=email";
public async Task<string> GetEmail(string accessToken)

{
    var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue
("OAuth", accessToken);
    var result = await client.GetStringAsync(FacebookIdentityUrl);
    var profileInformation = JsonObject.Parse(result);
    var email = profileInformation["email"].GetString();
    return email;
}

You may have noticed earlier that an API was used to save the token. Tokens have expirations and can be reused so you don’t have to force the user to login in repeatedly. A safe and secure way to store tokens that will even roam to other devices (provided the user uses their Microsoft Account and the devices are trusted) is the credential locker. The locker expects a resource (such as the name of the provider), a username, and a password. For this example, the username is fixed and the password is used to store the token and the expiration:

public void Save(string key, DateTime expiration, string token)

{
    var vault = new PasswordVault();
    var credential = new PasswordCredential(
        key, 
        Username, 
        string.Format("{0}|{1}", expiration, token));
    vault.Add(credential);
}

The vault can be queried for the credential and the expiration is used to determine whether the token can be used again or not. If the user requests to sign out, the credential is simply removed from the locker.

For a working code example visit http://winrtexamples.codeplex.com and download the Chapter 8 AuthenticationExamples app. It demonstrates single sign on and retrieval of email for both Facebook and Google. You will need to have developer accounts for each and will have to update the code with your client ids and client secrets for the project to run.