Google Authentication in Existing Universal Windows Platform(UWP) App Using Azure Mobile App SDK

This article will help you to setup the Google Authentication in a Windows 10 Universal Platform App using Azure Mobile App SDK.

Getting Started

For now let's hope you have already setup a blank project for Universal Windows Platform as we are considering connecting an existing App with Azure. I have named my solution as Win10GoogleAuthenticationDemo.

The App has a single page LoginPage.xaml

LoginPage.xaml





The Xaml code for the page is:

<Page  
    x:Class="Win10GoogleAuthenticationDemo.LoginPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Win10GoogleAuthenticationDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Resources>
        <Style x:Key="GoogleSignUpButtonStyle" TargetType="Button">
            <Setter Property="Background" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}"/>
            <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/>
            <Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundTransparentBrush}"/>
            <Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}"/>
            <Setter Property="Padding" Value="8,4,8,4"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
            <Setter Property="FontWeight" Value="Normal"/>
            <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
            <Setter Property="UseSystemFocusVisuals" Value="True"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal">
                                        <Storyboard>
                                            <PointerUpThemeAnimation Storyboard.TargetName="RootGrid"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <PointerUpThemeAnimation Storyboard.TargetName="RootGrid"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <VisualState.Setters>
                                            <Setter Target="ContentPresenter.(ContentPresenter.Background)">
                                                <Setter.Value>
                                                    <SolidColorBrush Color="#FFC73030"/>
                                                </Setter.Value>
                                            </Setter>
                                        </VisualState.Setters>
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="RootGrid">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseMediumLowBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <SolidColorBrush Color="{StaticResource SystemBaseHighColor}"/>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                            <PointerDownThemeAnimation Storyboard.TargetName="RootGrid"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="RootGrid">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledTransparentBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Button x:Name="GoogleSignUp"  Background="#FFDB4C3F" BorderThickness="0" Foreground="White" Height="30"  Margin="0,10,0,15" Width="240"  HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource GoogleSignUpButtonStyle}" Click="logIn" >
            <StackPanel  Orientation="Horizontal">
                <Viewbox Width="38" Height="20" HorizontalAlignment="Left" Margin="0">
                    <Canvas Width="27" Height="27">
                        <Path Data="M21.35,11.1H12.18V13.83H18.69C18.36,17.64 15.19,19.27 12.19,19.27C8.36,19.27 5,16.25 5,12C5,7.9 8.2,4.73 12.2,4.73C15.29,4.73 17.1,6.7 17.1,6.7L19,4.72C19,4.72 16.56,2 12.1,2C6.42,2 2.03,6.8 2.03,12C2.03,17.05 6.16,22 12.25,22C17.6,22 21.5,18.33 21.5,12.91C21.5,11.76 21.35,11.1 21.35,11.1V11.1Z" Fill="White" />
                    </Canvas>
                </Viewbox>
                <TextBlock Text="Log in With Google" Foreground="White" FontSize="14" Width="150"/>
            </StackPanel>
        </Button>
    </Grid>
</Page>
LoginPage.xaml.cs





The code for the LoginPage.xaml.cs :

using System;  
using System.Collections.Generic;  
using System.IO;  
using System.Linq;  
using System.Runtime.InteropServices.WindowsRuntime;  
using Windows.Foundation;  
using Windows.Foundation.Collections;  
using Windows.UI.Xaml;  
using Windows.UI.Xaml.Controls;  
using Windows.UI.Xaml.Controls.Primitives;  
using Windows.UI.Xaml.Data;  
using Windows.UI.Xaml.Input;  
using Windows.UI.Xaml.Media;  
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace Win10GoogleAuthenticationDemo  
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class LoginPage : Page
    {
        public LoginPage()
        {
            this.InitializeComponent();
        }

        private void logIn(object sender, RoutedEventArgs e)
        {

        }
    }
}

Now that the App is ready you will need a Azure Mobile App to be created for your App

Create a New Azure Mobile App

You will need to create a Azure Mobile App in your Azure portal. For this login to your Azure Portal and create a new Azure mobile App. Let's name it GoogleLoginDemo.

First in the Azure Portal Click on New on the blade that pop's up choose Web + Mobile which will then opens another blade with a list of Featured Apps. From the list select Mobile App . This is the starting point to configure your Azure Mobile App Backend.

Now name the Mobile App Service and choose a Subscription and Resource Group and click Create

After this you new Mobile App Will be added to your portal all up and running with a new blade will be opened with App details.The Url of the service is also provided in the blade

Visit the Url of your Mobile App and make sure the service is running . Here is the url of my app : http://googlelogindemo.azurewebsites.net

Register your application with Google

To complete the procedure in this topic, you must have a Google account that has a verified email address. To create a new Google account, go to accounts.google.com.

Log on to the Azure portal, and navigate to your application. Copy your URL. You will use this to configure your Google app

Navigate to the Google apis website, sign-in with your Google account credentials, click Create Project, provide a Project name lets name it LoginDemoAzure, then click Create

Under Social APIs click Google+ API and then Enable.

In the left navigation, Credentials > OAuth consent screen, then select your Email address, enter a Product Name, and click Save.

In the Credentials tab, click Create credentials > OAuth client ID, then select Web application

Paste the App Service URL you copied earlier into Authorized JavaScript Origins, then paste your redirect URI into Authorized Redirect URI. The redirect URI is the URL of your application appended with the path, /.auth/login/google/callback. For example my Url is , https://googlelogindemo.azurewebsites.net/.auth/login/google/callback.

Make sure that you are using the HTTPS scheme. Then click Create.

Now On the next screen, make a note of the values of the client ID and client secret.



Add Google information to your Azure App

Back in the Azure portal, navigate to your application. Click Settings, and then Authentication / Authorization.

If the Authentication / Authorization feature is not enabled, turn the switch to On.

Click Google. Paste in the App ID and App Secret values which you obtained previously, and optionally enable any scopes your application requires. Then click OK.

By this much you are almost ready all that left for you is to is to work with the UWP blank App that we created.



Add Authentication to UWP App

You will now have to modify the Win10GoogleAuthenticationDemo app that we created in the first step.

Install

Install the Azure Mobile App SDk with Nuget





Make sure that you install correct library Microsoft.Azure.Mobile.Client

Now you can connect the UWP App with the Azure Mobile App Service by adding the following code to App.xaml.cs

First add the dependency for MobileServices

using Microsoft.WindowsAzure.MobileServices;  

Now add the following code inside sealed partial class App.

// Connect to azure Mobile App Service   
        public static MobileServiceClient MobileService = new MobileServiceClient("https://googlelogindemo.azurewebsites.net/");

Now Modify the LoginPage.xaml.cs to call the Authentication for google ., you will have to add following code to LoginPage.xaml.cs

 // Define a member variable for storing the signed-in user. 
private MobileServiceUser user;  
private async System.Threading.Tasks.Task<bool> AuthenticateAsync()  
{
    string message;
    bool success = false;

    // This sample uses the Google provider.
    var provider = MobileServiceAuthenticationProvider.Google;

    // Use the PasswordVault to securely store and access credentials.
    PasswordVault vault = new PasswordVault();
    PasswordCredential credential = null;

    try
    {
        // Try to get an existing credential from the vault.
        credential = vault.FindAllByResource(provider.ToString()).FirstOrDefault();
    }
    catch (Exception)
    {
        // When there is no matching resource an error occurs, which we ignore.
    }

    if (credential != null)
    {
        // Create a user from the stored credentials.
        user = new MobileServiceUser(credential.UserName);
        credential.RetrievePassword();
        user.MobileServiceAuthenticationToken = credential.Password;

        // Set the user from the stored credentials.
        App.MobileService.CurrentUser = user;

        // Consider adding a check to determine if the token is 
        // expired, as shown in this post: http://aka.ms/jww5vp.

        success = true;
        message = string.Format("Cached credentials for user - {0}", user.UserId);
    }
    else
    {
        try
        {
            // Login with the identity provider.
            user = await App.MobileService
                .LoginAsync(provider);

            // Create and store the user credentials.
            credential = new PasswordCredential(provider.ToString(),
                user.UserId, user.MobileServiceAuthenticationToken);
            vault.Add(credential);

            success = true;
            message = string.Format("You are now logged in - {0}", user.UserId);
        }
        catch (MobileServiceInvalidOperationException)
        {
            message = "You must log in. Login Required";
        }
    }

    var dialog = new MessageDialog(message);
    dialog.Commands.Add(new UICommand("OK"));
    await dialog.ShowAsync();

    return success;
}

In the AuthenticateAsync method, the app tries to use credentials stored in the PasswordVault to access the service. A regular sign-in is also performed when there is no stored credential.

Now if you call the AuthenticateAsync method in the login button Click function

After all the changes the LoginPage.xaml.cs will have the following code.

using Microsoft.WindowsAzure.MobileServices;  
using System;  
using System.Collections.Generic;  
using System.IO;  
using System.Linq;  
using System.Runtime.InteropServices.WindowsRuntime;  
using Windows.Foundation;  
using Windows.Foundation.Collections;  
using Windows.Security.Credentials;  
using Windows.UI.Popups;  
using Windows.UI.Xaml;  
using Windows.UI.Xaml.Controls;  
using Windows.UI.Xaml.Controls.Primitives;  
using Windows.UI.Xaml.Data;  
using Windows.UI.Xaml.Input;  
using Windows.UI.Xaml.Media;  
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace Win10GoogleAuthenticationDemo  
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class LoginPage : Page
    {
        // Define a member variable for storing the signed-in user. 
        private MobileServiceUser user;

        public LoginPage()
        {
            this.InitializeComponent();
        }

        private async System.Threading.Tasks.Task<bool> AuthenticateAsync()
        {
            string message;
            bool success = false;

            // This sample uses the Facebook provider.
            var provider = MobileServiceAuthenticationProvider.Google;

            // Use the PasswordVault to securely store and access credentials.
            PasswordVault vault = new PasswordVault();
            PasswordCredential credential = null;

            try
            {
                // Try to get an existing credential from the vault.
                credential = vault.FindAllByResource(provider.ToString()).FirstOrDefault();
            }
            catch (Exception)
            {
                // When there is no matching resource an error occurs, which we ignore.
            }

            if (credential != null)
            {
                // Create a user from the stored credentials.
                user = new MobileServiceUser(credential.UserName);
                credential.RetrievePassword();
                user.MobileServiceAuthenticationToken = credential.Password;

                // Set the user from the stored credentials.
                App.MobileService.CurrentUser = user;

                // Consider adding a check to determine if the token is 
                // expired, as shown in this post: http://aka.ms/jww5vp.

                success = true;
                message = string.Format("Cached credentials for user - {0}", user.UserId);
            }
            else
            {
                try
                {
                    // Login with the identity provider.
                    user = await App.MobileService
                        .LoginAsync(provider);

                    // Create and store the user credentials.
                    credential = new PasswordCredential(provider.ToString(),
                        user.UserId, user.MobileServiceAuthenticationToken);
                    vault.Add(credential);

                    success = true;
                    message = string.Format("You are now logged in - {0}", user.UserId);
                }
                catch (MobileServiceInvalidOperationException)
                {
                    message = "You must log in. Login Required";
                }
            }

            var dialog = new MessageDialog(message);
            dialog.Commands.Add(new UICommand("OK"));
            await dialog.ShowAsync();

            return success;
        }

        private  async void logIn(object sender, RoutedEventArgs e)
        {
            // Login the user 
            if (await AuthenticateAsync())
            {
              // do something 
            }


        }





    }
}

Now if you run the Project the Google Authentication will work , look at the screen shot below to see the result.