Facebook Login for Windows Phone Apps

Friday, May 18, 2012 / Posted by Luke Puplett / comments (4)

The brief: allow new customers to sign up and sign in with their Facebook account, because they have this option on the website, so they’re going to need it in the phone app.
This is a high-level blog post about enabling Facebook login in a Windows Phone application. Once you’ve configured your app at and got your client/consumer ID and secret from developers.facebook.com, the process to actually authenticate your users is very simple - it’s the bigger picture that’s more difficult and so this blog post aims to prepare you rather than give you a few code snippets for what is essentially just extracting some tokens from a string.
So, with that said, these are the things to consider before writing any code:

  • How does OAuth work?
  • How will a Facebook account map to my accounts?
  • How does this affect my current secure authentication?
  • How will the login screen work on the phone?
  • What happens when the app has been slept for a long time?

How does OAuth work

Facebook uses a version of OAuth. Personally, I like learning specifications and writing my own code, rather than learning a framework or SDK. Usually, the spec is more clearly documented than other people’s SDKs.
Facebook has its own documentation covering how to authenticate, which I strongly advise you to read. The OAuth specification will give you a wider understanding, it’s pretty simple, but I must point out that Facebook doesn’t stick to the spec.
I’m going to explain the process in a nutshell here, but before I do that, consider that your application must register with Facebook and obtain a Consumer ID and Secret which will identify your app to Facebook. The aim is to get hold of an Access Token, which is a short-lived ticket that represents your rights to act on behalf of a Facebook customer.
  • There are a few types of authentication, depending on whether you’re building web apps or mobile/desktop/GUI apps.
  • For a web app, your server redirects the user to the Facebook OAuth sign-in page and passes across your Consumer ID so Facebook knows it’s issuing an Access Token for your app.
  • When doing so, you pass Facebook a URL to redirect back to, after the user signs in.
  • Your server ‘waits’ for the redirect and then extracts a temporary token from the redirect which it used to fetch the proper Access Token directly from Facebook, using an HTTP get.
  • For a client app with a UI, it’s much simpler.
  • Place a Web Browser control on a page and hook-up the Navigated event.
  • You automate the Web Browser control to navigate to the Facebook OAuth sign-in page, the user then logs in.
  • Facebook then redirects to a page you specify (at a domain you preconfigure with Facebook) and in the URL’s fragment portion, is the Access Token, as this occurs, the Navigated event fires a few times.
  • Inspect the Uri at each point to see if it has the Access Token or an error code. As soon as you have the token, you can progress the UI to the next stage.
  • You’re looking for access_token=xyz and expires_in=123 (seconds) parameters in the Fragment portion of the URI, it’s simply a case of parsing the string.

Why use Facebook to authenticate your customers?

Essentially, there are only a couple of reasons. The first is integration: you’d like your app to connect to Facebook and programmatically post to your customer’s feed or see who their friends are, perhaps. The second is to reduce sign-up friction and provide a better experience to the on-boarding process. This may be simply to remove the need for a customer to remember another password (and providing a way to reset forgotten passwords) or because your sign-up process asks a bunch of questions that you could actually just pull from their Facebook profile.
In the latter case, you’ll likely have your own customer entities in a database that will need to be linked to a Facebook account.

Mapping the Facebook account to your own accounts

If you’re retrofitting Facebook login to an existing app, then you’ve probably already got your own login process, so you’re going to need to offer a login screen supporting the old username and password sign-in as well as the new OAuth method.
As mentioned above, you might need to have a process for reading some details from Facebook and creating an account entity in your own system, and you may even wish to offer a way for users of the old sign-in scheme to connect their accounts.
I won’t go into detail about how to do this linkage, but whichever way you choose to accomplish it, you’ll need to ensure that another Facebook OAuth application cannot simply log-in to your app by just sending a Facebook ID to your login system.
Your server-side system should require the Access Token and user’s Facebook ID, and then use the Access Token against the Facebook Graph API directly to obtain the default FB account and check the ID for the user it returns matches what you’ve been sent.
You’ll also need to prove that the Access Token and user ID have come from your app, so you’ll need to sign the data with a secret that’s shared between your servers and your app, which means obtaining/agreeing a key before the Facebook sign-up occurs.
If you don’t do this, then there’s nothing to stop another Facebook app from getting an Access Token and FB user ID and sending them to your login endpoint and masquerading as one of your customers!
There’s an inherent weakness here, in my opinion, that could be strengthened if, when your server fetches the user account using the supplied Access Token from Facebook, you supply your App Secret and FB could ensure that the Access Token was issued to your app.

How will the login screen work on the phone?

If you don’t have an existing login scheme then you only need to supply the Facebook login option, unless for privacy reasons, you’d like to allow your customers to sign-up without Facebook.
It’s safe to assume that login will take place from a dedicated page, as opposed to a popup control. The user should only be bothered by the login screen when they need to login, and that page needs to play host to a web browser.
We also need to consider sign-up, as well as sign-in; your application may need to collect extra information on sign-up, data that’s not available from Facebook, but also, your customers might not want to use Facebook.
In my scenario, I have a dedicated page and flow for non-Facebook sign-up, and a dedicated page and flow for Facebook sign-up and sign-in (combined).
The flow goes something like this:
OAuth Page Flow
The left-most page is the Home Panorama which detects a guest login and provides two menu options for logging-in and signing-up.
The top path consists of:
  • The Login Method Selector page, offering the Facebook login and a normal username + password UI.
  • Using the latter will call the normal login web service and follow the quick route back to the Home page, while selecting Facebook login, will navigate to a page with a Web Browser control.
  • This page will display the standard Facebook OAuth login screen and upon entering details, the browser control will vanish and, if the customer is signing-up, they’ll be presented with a page through which they can supply a screen-name, otherwise, if logging-in, they’re just navigated to the Home page.
  • If sign-up goes well, then a welcome message is displayed and the user is offered the option to post a Wall message or click to go straight to the Home page.
The bottom path consists of:
  • The Sign-up Method Selector page, offering Facebook and ‘Manual’.
  • The Facebook option takes the user to the top flow, whereas the manual route consists of a few more pages / UI that collects and checks all the extra data that’s needed to create an account, data that is normally taken from their FB account details.

What happens when the app has been slept for a long time?

Login credentials are persisted between app use sessions and the Home page is able to detect which login method the user used last time. For a Facebook login, the previous Facebook Access Token is verified and, if expired, the app navigates to the Facebook login page and brings up the Web Browser control.
If the Web Browser has cached login details then the browser will automatically be logged-in, without the user typing anything, and the app will navigate back to the Home page. This flow happens so quickly that it appears that the app opens at the Facebook page, looks busy for a couple of seconds and then goes to the Home page.
This flow might take some time on slow networks but Manual logins can simply authenticate without navigating anywhere and work much more smoothly.
So far, this is all fine and dandy, but in reality the Home page is not the first page of an app. An app may be entered via the back button or on resume, into a state where the user is no longer considered logged-in – the Access Token has expired or your server session has been pruned.
In my app, I use my own MVCVM pattern. I have a Controller in addition to the ViewModel. This is just a personal preference, I like to keep my ViewModels as just ‘binding and commanding surfaces’ with no logic.
Doing things this way keeps me from adding spiralling side-effect logic in property setters and coerces me to use dedicated helper and utility classes rather than be tempted to inherit too much application logic - I’ve worked on apps that reuse logic by VM subclassing and it gets ugly. I also like to build standard ‘dumb’ VMs which can be reused across the app and contain only what needs to be on the screen.
Saying that, I do use inheritance in this situation. My base PageController has a set of virtual methods which orchestrate all the initialization, one of which is called to check authentication.
Each time a page is navigated to, the PageController runs some code to ensure the user is logged-in which allows me to redirect the user to the Login page and return afterwards using the BackStack. I also check the BackStack and remove the sign-in pages so the user can’t back into them.
With this logic on each page, even if the user lets the phone go idle overnight while on a page deep within my app, the Login flow will run in the morning, as soon as the page resumes.
Of course, you don’t have to have funky Controllers and virtuals to do this, but it needs bearing in mind that authentication isn’t just something that happens on the Home screen.
Time will tell whether this page flow method works. It’s perfectly feasible to embed a Web Control in a popup UI control or inject it into the visual tree. As networks get faster (I’m looking at you, 4G), then Facebook login will become a less irksome UI dance.
Have fun, and here’s some useful links:
Facebook Authentication Documentation
http://developers.facebook.com/docs/authentication/
OAuth 2.12 – although Facebook strays from the standard in some fairly major ways.
http://tools.ietf.org/pdf/draft-ietf-oauth-v2-12.pdf
Where Facebook veres from the OAuth standard.
http://stackoverflow.com/questions/9724442/is-facebooks-oauth-2-0-authentication-a-strict-implementation-of-the-rfc

Labels: , , , , ,

Windows Phone Panorama background image cropped when smaller than screen size.

Wednesday, May 16, 2012 / Posted by Luke Puplett / comments (0)

CroppedPerfect

Notice that the background image repeats just before the ‘r’ on the right side of the left image, but its fine on the other image.

This image on the left is 512x384 whereas the image on the right is twice the size, 1024x768. It seems that when the image must be stretched to fill the height of the screen, the width is truncated. When an image must be shrunk to fit, then the width is preserved.

The Sretch property isn’t required for the larger image, but it works when set as Fill or UniformToFill. The smaller image needs UniformToFill to look correct.

Labels: , ,

Detecting Windows Phone Screen Size

Monday, November 15, 2010 / Posted by Luke Puplett / comments (0)

Eventually, and probably not long from now, the Windows Phone will have a form factor that isn’t 480 x 800 so here’s how to detect the screen size:

protected PhoneViewModel()
{
    this.ScreenWidth = System.Windows.Application.Current.Host.Content.ActualWidth;
    this.ScreenHeight = System.Windows.Application.Current.Host.Content.ActualHeight;
}

Labels: , , ,

WPF Font Rendering Side-by-side

Thursday, March 04, 2010 / Posted by Luke Puplett / comments (0)

Text rendering in Windows Presentation Framework has been a moot point since its release. Microsoft are responding to this and in WPF 4.0 text rendering will be performed by DirectWrite, some new bit of DirectX. But still, while working on reproducing a mockup done in Corel PHOTO-PAINT, I wanted to get to the bottom of why I am never happy with WPFs rendition and whether I am just imagining the whole thing.

My original mock-up was done in Corel's Photoshop equivalent at a very high resolution and then I view it in a normal viewer like Windows Live Photo Gallery and zoom it down to the right size.

I then compare my WPF work with the mockup PNG side-by-side and usually squint and shake my head alot.

So I created the same thing in CorelDRAW and Microsoft Word, giving me a total of 4 versions of the same mockup. Here's what I discovered.

Font Render Side-by-side

For me, Corel's versions are the nicest. I just like them more, in the way that I prefer one woman's face over another. It's subtle and innate.

Philosophy aside, the WPF version and the Corel could easily be mistaken for different typefaces. They're both Swiss 721 Lt BT. Here's my analysis:

  • Corel renders the O under the T, probably because it doesn't need to consider text selection. This is it primary advantage.
  • Corel apps and Word seem to render the lowercase glyphs slightly larger (1px) so that there is less of a difference in height to the uppercase T.
  • The top right end of the s in WPF sinks down, caused by confused anti-aliasing.
  • Word uses coloured anti-aliasing, blue on one side of the T and red on the other - the others do not.
  • WPF renders the thickest, most woolly lines.
  • WPF also renders the horizontal bar in e lower than the others, probably because it is slightly smaller and the bar snapped down a pixel.
Font Render Side-by-side Zoomed

As far as I see it, the fact that Microsoft Word can render the text quite accurately, the issue is not solely about ClearType but something inherent in WPF. It's a shame that text cannot be tuned per XAML element with varying amounts of anti-aliasing instead of on/off.

I hope they work it out in 4.0.

Labels: , , ,

Linq to Visual Tree

Friday, November 20, 2009 / Posted by Luke Puplett / comments (0)

Over on Peter McGrattan’s blog is a simple extension method for a DependencyObject which returns the visual tree descending from a particular visual element in a WPF application. The genius in Peter’s simple extension is that it automatically leverages the power of LINQ because the tree is IEnumerable:

myPanel.GetVisualOfType<TextBox>().Where(t => t.Foreground... etc

But I had a problem: the tree would not descend fully.

To cut a long story short, the issue was caused because VisualTreeHelper.GetChildrenCount doesn’t count the content of a ContentControl as a child.

The following is my version of Peter’s good work – this is just one method cut from the original class, so I implore you to head over to his blog and see the whole thing. I have made the following changes:

  • Added support for ContentControl objects.
  • Modified the type checking to use IsAssignableFrom so types can be collated using their base classes.
public static IEnumerable<T> GetVisualOfType<T>(this DependencyObject element)         

    return GetVisualTree(element).Where(
        t => typeof(T).IsAssignableFrom(t.GetType())).Cast<T>();
}
public static IEnumerable<DependencyObject> GetVisualTree(this DependencyObject element)
{
    int childrenCount = VisualTreeHelper.GetChildrenCount(element);

    if ((childrenCount == 0) && (element is ContentControl))
    { 
        ContentControl cc = element as ContentControl;
        if (cc.Content != null)
        {
            DependencyObject content = cc.Content as DependencyObject;

            if (content != null)
            {
                yield return content;
                foreach (DependencyObject obj in GetVisualTree(content))
                    yield return obj;
            }
        }
    }

    for (int i = 0; i < childrenCount; i++)
    {
        var visualChild = VisualTreeHelper.GetChild(element, i);
        yield return visualChild;
        foreach (var visualChildren in GetVisualTree(visualChild))
        {
            yield return visualChildren;
        }
    }
}

Labels: , ,

One Service + Two Client Platforms = Misery

Friday, May 08, 2009 / Posted by Luke Puplett / comments (0)

Aim: I want to be able to transmit a username and password hash and see it easily from within the service.

My idea of Hell is WCF. I liked .NET Remoting and I got on with Web Services, but the unified Windows Communication Foundation is a quagmire of configuration and complexity, not least because its half-merged with IIS, which is sort of merged but not merged with ASP.NET.

Today, I am tackling the issue of using the same WCF Service that my Silverlight client uses, for a fat desktop client.

Making a Meal of WCF and Cookies

The scenario to the uninitiated might look straight-forward, after all I’m connecting two Microsoft .NET-based products to a Microsoft .NET-based SOAP service, all running in the same VS solution on one box.

The problem is that Silverlight runs in the browser and has an authentication scheme which uses its host browser’s HTTP stack and cookies, while the other client, despite being fat, has never even seen a cookie.

To be clear, my WCF services end uses Microsoft’s AuthenticationService to provide Forms authentication behaviour over the HTTP connection between SL client and service, which basically does the cookie creation and response so I don’t have to. This works great but I what about my non-Silverlight clients?

While Jonas Folleso has one solution to the problem, by detaching the authentication cookie and sticking it back on to all outgoing headers, I wanted to take the ‘easier’ route: exposing another service end-point that supports some kind of authentication.

I want to do this because I want my client to sign-in using the SSL secured AuthenticationService, set-up a session with some shared secret key and then in all subsequent requests to my other services, send over a hash of something using the shared secret.

I’m actually writing this as I work on it, so as these words are being typed, I don’t know what to expect.

Step One: Add a new EndPoint and connect to it

I add a new EndPoint to the web.config of my IIS service host, using the same basic binding as the working service, just for simplicity and testing.

<endpoint address="/vpr"
binding="basicHttpBinding"
contract="IUserService"
/>

Lesson - While doing this, I learn that the <baseAddresses> section is pointless on IIS because its IIS and the base address will be wherever the .svc files are.

I copied the chunk of XML that defines the mex endpoint, and like mex and according to MSDN, my service endpoint address will be relative to the base URL which is the svc file, I presume.


Adding a Service Reference to any of the URLs above fails with error saying:


The request failed with HTTP status 400: Bad Request. Metadata contains a reference that cannot be resolved: 'blah'.

Lesson – You only need to point the Add Reference box to the .svc file and the other endpoints are read from the WSDL (you can see this because the client app.config will fill with the server endpoints).

mex is an exception to the rule and can be referenced by putting /mex after .svc, also the discover option doesn’t see the endpoint as being a different service.

This is all how it should be and I think endpoint addresses are actually just ID strings which help WCF route messages into the right worker queue for processing on the server but are structured as URLs to confuse you.

Step Two: Choose a Binding

The aim is simply to choose a binding which puts the plumbing in place for me to transmit credentials. So first up, I try just setting ClientCredentials.UserName to something useful and checking it on the server via ServiceSecurityContext.Current, but get a null ref exception.

I also try disabling anonymous logon from the IIS console in case this is causing my username to be lost, but this causes everything to break – I can’t even connect to get the service description.

Lesson – Ignore the bit about disabling anonymous access.

I persist with the trusty basicHttpBinding because MSDN says:

By default, the BasicHttpBinding class does not provide security. This binding is designed for interoperability with Web service providers that do not implement security. However, you can switch on security by setting the Mode property to any value except None. To enable transport security, set the property to Transport.

I do as it says but I get this error upon updating my Service Reference:

Could not find a base address that matches scheme https for the endpoint with binding BasicHttpBinding. Registered base address schemes are [http].

The problem is that I don’t want to use HTTPS. Time to try another tack: Message Security, which MSDN tells me

means that every message includes the necessary headers and data to keep the message secure. Because the composition of the headers varies, you can include any number of credentials. This becomes a factor if you are interoperating with other services that demand a specific credential type that a transport mechanism can't supply, or if the message must be used with more than one service, where each service demands a different credential type.

Here goes nothing.

        <binding name="vpr">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>

I refresh my Service References and receive:

BasicHttp binding requires that BasicHttpBinding.Security.Message.ClientCredentialType be equivalent to the BasicHttpMessageCredentialType.Certificate credential type for secure messages. Select Transport or TransportWithMessageCredential security for UserName credentials.

Right then. TransportWithMessageCredential it is, or at least it would be but that of course leads me right back to:

Could not find a base address that matches scheme https for the endpoint with binding BasicHttpBinding. Registered base address schemes are [http].

An MSDN article on using the ASP.NET Membership Provider reckons I can use WSHttpBinding set to Message Security to transmit a user name, but goes on to talk about adding service behaviours for the membership provider. I will try most of it (as I don’t want to use the ASP.NET MemProv). I put

    <serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"/>
</serviceCredentials>

..in the behaviours element with this in the binding element:

    <security mode="Message">
<message clientCredentialType="UserName"/>
</security>

But this gives this error when adding/updating the Service Reference:


UserNamePasswordValidationMode.Custom requires a CustomUserNamePasswordValidator. Specify the CustomUserNamePasswordValidator property.


I may be on to something... searching microsoft.com reveals an article entitled User Name Password Validator.

So I’ve written a test class called CookielessCredentialValidator which extends System.IdentityModel.Selectors.UserNamePasswordValidator and just throws a NotImplementedException on the only overridable method is has, Validate() and changed my web.config:

<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="App.Web.CookielessCredentialValidator"/>

Upon updating my service reference I get:


Could not load type ‘App.Web.CookielessCredentialValidator’ from assembly ‘System.ServiceModel, Version=3.0.0.0, Cul... etc.

Looking back at the MSDN article I realised that I need to format the type name differently, prefixing my derived class with the name of my service class and maybe the word service after it? Not really clear and the article on customUserNamePasswordValidator provides no help:

Looking further into this, it seems that I must create an X509 Certificate.

Lesson – You can’t send credentials without HTTPS or some other encryption method in the .NET Framework, even if you do have you own method for encrypting the data you wish to put in the username and password properties.

Step Three: Go back to Jonas Folleso’s Blog and do what he did

...and pray that Microsoft changes this nannying part of the framework before I get customers trying to use my service from a platform that can’t fiddle around with cookies.

The End.

P.S. Sorry about the extra space around blockquotes, the Blogger system seems to want to add breaks each and every time I place a carriage return in pure HTML - bizarre and annoying in equal measure.

Labels: , , , ,

Silverlight to Service Layer: Sharing a CoreLib

Monday, April 27, 2009 / Posted by Luke Puplett / comments (0)

Technorati Tags: ,,

We all know that sharing is caring but when it comes to Microsoft’s RIA client you may find sharing is tearing, your hair out. In this post I will explain how you can code a class once but use it in both your WCF service, and the Silverlight codebase that consumes it.

While architecting a cross-browser web app, I made a big assumption: that Microsoft’s RIA platform would be CLR-based and so my types could be passed (via WCF) though all my tiers; with a simple Add Reference from Silverlight, I’d have access to all my business entities. As it turned out, I couldn’t.

True, Silverlight has the CLR we all know and love, but it ain’t the same CLR. While the Add Reference dialog will lead you up the garden path to your full-fat assembly, the sucker punch goes like this...

“You can’t add a reference to AmazingLibrary.IspentAgesWriting.dll as it was not built against the Silverlight runtime. Silverlight projects will only work with Silverlight assemblies.”

So where to go from here? The answer is to share your code files. The VS 2008 IDE (I haven’t looked in 2005) allows you to link a project to source files with the click of its often overlooked combo-button - I know this is often overlooked because I’ve seen others hacking around with their solution files to achieve the same thing.

 
Right click on the Silverlight project or a folder you have within it and choose this option:

01.Add Existing Item Menu

 
Then take the Add dialog to where you store the code files for your full-fat assembly or types but instead of hastily stabbing at the Add button, drop it down and choose Add As Link:

02.Add As Link Menu

 

You can highlight and link multiple files using CTRL, although once linked you will need to be aware of a few more things.

  1. All edits are shared - because its now linked - but the VS editor will be ‘wearing the context’ of whichever type of project the file was opened from.

    If you double-click the file under your Silverlight project tree it will impose the Silverlight context, such as intellisense, references from the Silverlight project and stuff that just isn’t included in the skinny SL CLR.

  2. You may also need to use the new SILVERLIGHT compiler keyword to section-off lumps of code that don’t compile in SL and section-in alternatives that do.

    #if
    !SILVERLIGHT
        using FullCLR.Types
    #endif

  3. If, like me, you’re sharing entity types for marshalling between a WCF service and a SL client, you may need to add data contract names and namespaces and then update your service references. Of course, you only need to add this once on each shared class.

    /// <summary>

    /// Represents a finite period of time with a start and end.
    /// </summary>
    [DataContract(
        Name = "TimeRange"
        Namespace = "http://schemas.co.com/2008/11/entities")]
    public sealed class TimeR...

    When you hit build, the compiler’s going to ensure that the same data contract metadata ends up in both the service and the client libraries and so when you add a service references, the proxy should map these types rather than generate classes.

     

Note that sharing entities in this way may not be suited to your design philosophy or coupling strategy and that code in the classes that forms the Silverlight client will be publicly available for scrutiny. In my own project I use this technique for ‘hollow’ data contract entities that otherwise contain no business logic.

Luke

Labels: , , ,