Thursday, 12 January 2017

Integrate Facebook with your UWP app

Let's start with, yes I realize that UWP stats for Universal Windows App so my title is redundant, but no matter.

Let's get started first we'll start with the Microsoft App part, start by going to https://developer.microsoft.com/en-us/dashboard/apps/overview this is where all of your applications are listed, or will be listed.

Here we're going to hit that big blue button [Create a new app]
Now here, we're going to very carefully reserve our product name, this way when we're drunk and talk about the killer app we have our brilliant name reserved (by the time this post is published i'll release the name so one lucky person can grab it).

so we are going to have to get our applications unique id and at the time of this blog post you would get it form App management->App identity


(however that will probably change within 10 minutes of me publishing my app, just know that your're looking for the Package SID, it'll look something like
S-1-15-2-2635956083-3616007119-1179820000-4100729299-1155630488-2187398330-765838093)\

with that done next we have to configure our Facebook app, i know wtf configure two apps and we still haven't written a line of code. we'll accomplish that through the facebook developer portal, you'll have to set up an account, but i'll leave that to you.

anyway navigate to https://developers.facebook.com/apps/


so guess what? Click the button [Add a New App]

so now we give our app a display name, i've blocked my email, because i don't want to be part of your bizarre minuter figurine mailing list, but that's where you're facebook email would go.
Right after that you're gonna have to fill out a captcha, cause i guess it's 2010

now finally you're app is up and running


you have your app id:248051828941912 which is great, but now for configuring the two to work together, go to the settings section

here you'll have to add a platform

obviously pick the window app one

here's where we enter in the sid that we got from our Microsoft App we registered before. and make sure to hit the save changes button.

next hit the add product in the right hand column

Next select other

next click the Manually build login flow
This wont do anything for you, but read the resulting page https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow it'll help a lot.

Now hit the settings in the left hand panel
and make sure that your client OAuth login is available and ensure that you've set the valid OAuth redirect to "https://www.facebook.com/connect/login_success.html"

Finally 50 clicks later we can start our app, so go ahead and create a new visual studio project. Now I've created a blank app, in my blank app i've created a folder call Services and in that folder i created a Class called Facebook service; why i don't know, at some point that became the cool name for what was formally known as helpers and before that handlers, but that's neither here nor there. this is what i have for a solution explorer.
Now normally i'd create viewmodels, views and models folders, but this post is already way longer then i wanted it to be. Open up the FacebookService.cs class

The basics of authenticating to facebook is:

  • your UWP app calls your Facebook app
  • your facebook app asks for your user credentials
  • if the credentials are valid it passes you back a token with a time duration it's valid for
  • otherwise you get an exception when you call the facebook graph api (https://developers.facebook.com/docs/graph-api
so let start with building a container for our token 

class fbToken
{
    public string Token
    {
        get
        {
            if (_expiration > DateTime.Now)
                return _token;
            return null;
        }
    }
    DateTime _expiration;
    string _token;

    public fbToken(string webAuthResultResponseData)
    {
        if (String.IsNullOrEmpty(webAuthResultResponseData))
            throw new ArgumentNullException("webAuthResultResponseData", "Token not provided");

        var pattern = @"#access_token=(?<accessToken>\w+)&expires_in=(?<expiresIn>\d+)";
        var regexResult = Regex.Match(webAuthResultResponseData, pattern);

        _token = regexResult.Groups["accessToken"].Value;
        var seconds = regexResult.Groups["expiresIn"].Value;
        _expiration = DateTime.Now.AddSeconds(Convert.ToInt32(seconds));

        Debug.WriteLine("access_token = " + _token);
        Debug.WriteLine("expires_in = " + _token);
    }
}

now in the constructor we take in a parameter "webAuthResultResponseData" this is the result from when we request our token it looks something like this:
https://www.facebook.com/connect/login_success.html
#access_token=EAADhmhEmZAFgBAIHfupZBOoGQzcZCP4VY1GTQqjRFEl27F9DcqIHEJQiyRA39dAZAj3oIsF40IanUjMOJNNzhufGmGBdSTykMMIfLsEV1XROZCVpSJEaC3SprhVCDHful49uescbjs8ZB0dyiBFMph4ZCIkCvFZBAFTcbqjgfQZA4HwZDZD
&expires_in=4993
the token part needs to be accompanied with each call to the graph api and the expires in is how many more seconds the token is valid for. 

next let's create our FacebookService class

class FacebookService
{
    string FacebookAppId = Uri.EscapeDataString("248051828941912");

    string FaceBookRedirectUrl = "https://www.facebook.com/connect/login_success.html";

    string scope = "public_profile";
    //https://developers.facebook.com/docs/facebook-login/permissions

    string FacebookOAuthURL = $"https://www.facebook.com/dialog/oauth?" +
        "client_id={0}&"+
        "redirect_uri={1}&"+
        "scope={2}&"+
        "display=popup&"+
        "response_type=token";

    fbToken fbToken { get; set; }

    private async Task<string> Connect()
    {
        string fbURL = String.Format(FacebookOAuthURL, FacebookAppId, FaceBookRedirectUrl, scope);
        Uri StartUri = new Uri(fbURL);
        Uri EndUri = new Uri(FaceBookRedirectUrl);

        WebAuthenticationResult WebAuthenticationResult =
            await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, StartUri, EndUri);

        switch (WebAuthenticationResult.ResponseStatus)
        {
            case WebAuthenticationStatus.Success:
                return WebAuthenticationResult.ResponseData.ToString();
                   
            case WebAuthenticationStatus.ErrorHttp:
                Debug.WriteLine("HTTP Error returned by AuthenticateAsync() : "
                    + WebAuthenticationResult.ResponseErrorDetail.ToString());
                break;
            case WebAuthenticationStatus.UserCancel:
                Debug.WriteLine("Error returned by AuthenticateAsync() : "
                    + WebAuthenticationResult.ResponseStatus.ToString());
                break;
            default:
                Debug.WriteLine("C'est Bizare");
                break;
        }
        return null;
    }

    public async Task<string> GetUserNameAsync()
    {
        //Get Access Token first
        if (fbToken == null || String.IsNullOrEmpty(fbToken.Token))
            fbToken = new fbToken(await Connect());

        //Request User info.
        var httpClient = new HttpClient();
        string response = await httpClient.GetStringAsync(
            new Uri($"https://graph.facebook.com/me?access_token={fbToken.Token}"));

        var responseValue = JsonValue.Parse(response).GetObject();

        return responseValue.GetNamedString("name");
    }

}

this class has two methods
  • Connect: which just gets the token and only needs to be called when we don't have a token or it's expired
  • GetUserNameAsync: which just makes an http request to the facebook graph api for our user info

four fields
  • FacebookAppId: which is the id of our facebook app that we created way above
  • FacebookRedirectUrl: which is required by the facebook app to complete the call back, remember we set it back in the facebook application as the valid OAuth redirect URI
  • Scope: which specifies what permissions we are asking for (Ie profile, friends list, birthday, etc) see for more (https://developers.facebook.com/docs/facebook-login/permissions)
  • FacebookOAuthUrl: the address where we make our call to request a token
one property
  • fbToken: a container for our token 

while we are at it let's create a UI

<Page
    x:Class="pc.FacebookApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:pc.FacebookApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
          HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel>
        <Button Click="Button_Click" Content="Connect to FaceBook"/>
            <TextBlock x:Name="UserName" />
        </StackPanel>
    </Grid>
</Page>

It should look something like

next the codebehind

using pc.FacebookApp.Services;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace pc.FacebookApp
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }
        FacebookService fbService = new FacebookService();
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            UserName.Text = $"Hello {await fbService.GetUserNameAsync()}";
        }
    }
}


not exactly rocket science and finally what happens when you connect to facebook

first you get a modal to authenticate yourself
Once that's done your app should go and get your facebook display name
And that's all she wrote.