Implementing Google login in Universal Apps

In a recent project I had to implement Google login to an Universal App. I decided to use the native WebAuthenticationBroker control and the implementation was not as straightforward as I hoped. By implementing Google login I mean getting the authentication token that you can then use with your server API.

WebAuthenticationBroker is a good idea but it is implemented rather poorly. It works differently on Windows 8.1 and Windows Phone 8.1 due to the “AndContinue” pattern that Windows Phone 8.1 forces on you. You can solve this with some ifdefs and platform specific code, as always.

The real problem s that the MSDN sample states it works with Google login but it does not. The sample thinks it gets the authentication token but it does not, it just gets the success code that you have to exchange for the authentication token yourself.

Lets start with a basic config

internal static string GoogleAppId = "your google app id";

internal static string GoogleAppSecret = "your google app secret";

internal static Uri GoogleStartUri = new Uri("https://accounts.google.com/o/oauth2/auth?client_id=" + Uri.EscapeDataString(GoogleAppId) + "&redirect_uri=" + Uri.EscapeDataString("urn:ietf:wg:oauth:2.0:oob") + "&response_type=code&scope=" + Uri.EscapeDataString("profile https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.me email"));

internal static Uri GoogleEndUri = new Uri("https://accounts.google.com/o/oauth2/approval?");

The important things here are your Google app id and Google app secret. The GoogleStartUri also contains permissions that you want to get (profile, https://www.googleapis.com/auth/plus.login and https://www.googleapis.com/auth/plus.me email in my case).

You use this config with a WebAuthenticationBroker call

#if WINDOWS_APP
    var auth = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.UseTitle, Config.GoogleStartUri, Config.GoogleEndUri);
    Debug.WriteLine(auth.ResponseData);
    
    var successCode = GetGoogleSuccessCode(auth.ResponseData);
    var token = GetToken(successCode);
    //do something with the authentication token
#else
    WebAuthenticationBroker.AuthenticateAndContinue(Config.GoogleStartUri, Config.GoogleEndUri, null, WebAuthenticationOptions.UseTitle);
#endif

on Windows 8.1 you get the response data immediately. On Windows Phone 8.1, you have to implement the “AndContinue” pattern.

You use the response data to parse out the success code

private string GetGoogleSuccessCode(string data)
{
    if (string.IsNullOrEmpty(data)) return null;
    var parts = data.Split('=');
    for (int i = 0; i < parts.Length; ++i)
    {
        if (parts[i] == "Success code")
        {
            return parts[i + 1];
        }
    }
    return null;
}

Now that you have the success code, you can exchange it for the authentication token

And now you finally have a way to get the authentication token and implement Google login.

public async Task<string> GetToken(string code)
{
    var client = new HttpClient();
    var auth = await client.PostAsync("https://accounts.google.com/o/oauth2/token", new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("code", code),
        new KeyValuePair<string, string>("client_id",Config.GoogleAppId), 
        new KeyValuePair<string, string>("client_secret",Config.GoogleAppSecret), 
        new KeyValuePair<string, string>("grant_type","authorization_code"),
        new KeyValuePair<string, string>("redirect_uri","urn:ietf:wg:oauth:2.0:oob"),  
    }));
    
    var data = await auth.Content.ReadAsStringAsync();
    Debug.WriteLine(data);
    var j = JToken.Parse(data);
    var token = j.SelectToken("access_token");
    return token;
}

See also