Hackviking He killed Chuck Norris, he ruled dancing so he took up a new hobby…

11Nov/1421

Facebook API login flow for desktop application

Facebook like

When developing desktop applications that interacts with Facebook you have to implement the login flow your self. After the login flow completes you can use the normal Facebook SDK libraries by supplying it with the access token your received. When implementing the login flow you have to make sure that you receive the access you requested. You can get a partial approval by the user and not be able to access all the scopes you need. In this example I have implemented the Facebook login flow into a C# .Net desktop application. Full source is available for download.

Basics of the Facebook login flow

Most of the information about how to implement your own Facebook login flow can be found in Facebook's developers article Manually Build a Login Flow. The basics for doing this from a desktop application is to send the user to the Facebook site for authentication in a web browser control. This is the same way a web application would be implemented but instead of using return (redirect_uri) that goes back to your server you send the user to https://www.facebook.com/connect/login_success.html instead. The returned information will then be added as url fragments. Url fragments are also know as bookmarks, the information behind the # in an url. At the same time any errors will be passed back as query string parameters, behind the ? in the url, so you have to check for that as well. Besides from that the implementation is pretty straight forward.

Prerequirements

Before you can send the user into the login flow you need to register a Facebook application. Use the "advanced setup" option to create it. After your created your application make a note of the application ID for later. Then go in to the application settings and select the "advanced" tab. Make sure that your set the following:

  • Native or desktop app? - Yes
  • Client OAuth login - Yes
  • Embedded browser OAuth Login - Yes

Display the dialog

FBDialog fbd = new FBDialog({your-application-id}, {comma-delimited-list-of-scopes});
fbd.ShowDialog(this)

This will show the Facebook login dialog. The implementation attached in the example code uses an extended version of the windows form web browser control. This extended version is used to be able to detect the javascript trying to close the dialog. The code for this extension is included in the example. Credit to Mrojas @ Artinsoft, the original code and article.

When the dialog loads the return url, mentioned above, and the comma delimited list of scopes are url encoded. Then we build the url and navigate to it.

string returnURL = WebUtility.UrlEncode("https://www.facebook.com/connect/login_success.html");
string scopes = WebUtility.UrlEncode(p_scopes);
FBwebBrowser.Url = new Uri(string.Format("https://www.facebook.com/dialog/oauth?client_id={0}&redirect_uri={1}&response_type=token%2Cgranted_scopes&scope={2}&display=popup", new object[] { p_appID, returnURL, scopes }));

We also attach an event handler for when the browser navigates.

FBwebBrowser.Navigated += FBwebBrowser_Navigated;

The login flow

Now the user is presented with the login screen and information about what application they will authenticate by logging in. The user have several options here:

  • The user can click cancel at once and close the dialog. The FBDialog will then return DialogResult.Cancel.
  • The user can login and authenticate your app but edit the scopes you are allowed to access. FBDialog will then return DialogResult.OK and you will be able to retrieve which scopes was approved. See below under "Return values".
  • The user can login and then click abort/cancel. The FBDialog will then return DialogResult.Abort. This will also be the result in case of an error. See below under "Return values".

During the users interaction with the login flow the FBwebBrowser_Navigated function will fire every time the browser navigates to a new page/url. During this it will just set the title of the window to the same as the current document title until it hits the return url.

if (FBwebBrowser.Url.AbsolutePath == "/connect/login_success.html")
{
    // Check for error
    if (FBwebBrowser.Url.Query.Contains("error"))
    {
        // Error detected
        this.result = System.Windows.Forms.DialogResult.Abort;
        ExtractURLInfo("?", FBwebBrowser.Url.Query);
    }
    else
    {
        this.result = System.Windows.Forms.DialogResult.OK;
        ExtractURLInfo("#", FBwebBrowser.Url.Fragment);
    }
    // Close the dialog
    this.Close();
}

If an error is detected it will extract the error information, which is then available as public properties on the FBDialog object and return DialogResult.Abort. If the login is successful access token, expires and granted scopes will be available as public properties on the FBDialog object and it will return DialogResult.OK.

Return values

The dialog returns a standard DialogResult that can be used like this:

switch (fbd.ShowDialog(this))
{
    case DialogResult.Abort: // There was an error
        break;
    case DialogResult.Cancel: // User clicked cancel or closed the dialog
        break;
    case DialogResult.OK: // Logon successfull
        break;
    default:
        break;
}

If DialogResult.Abort is returned there are three public read-only properties available on the FBDialog object.

  1. FBDialog.error - name/type of the error
  2. FBDialog.error_reason - why the error was raised
  3. FBDialog.error_description - a brief description of the error

If DialogResult.Cancel is returned the user clicked cancel before logging in or closed the dialog.

If DialogResult.OK is returned the user logon was successful. However the user might not have granted you all the scopes you requested. There are several public read-only properties with information after a successful login.

  1. FBDialog.access_token - the access token string that can then be used for further requests against Facebook APIs.
  2. FBDialog.token_expires - a DateTime object representing the when the access token expires.
  3. FBDialog.granted_scopes - a comma separated list of scopes that the user granted you access to.
  4. FBDialog.denied_scopes - a comma separated list of scopes that the user denied you access to.

Conclusion

The implementation is pretty straight forward to use. The modification to the web browser control is only cosmetic but makes the flow work as users are use to in online apps. When you have received your access token you can use the Facebook SDK .Net for further interaction with the API. A great way to check out what you can do with the Graph API and what properties will be available on the objects is to use the Facebook Graph API explorer. Some scopes needs additional permissions from Facebook to use, but are all available to you for testing during the development process, more information is available on the Facebook Developers site.

This code can be used by anyone for any purpose but please link back and give credit!

Source code:


Source code @ Github

Comments (21) Trackbacks (0)
  1. Hey,

    im just implementing facebook within desktop app, just on OS X (modified ios facebook sdk with ui elements changed). I`ve encountered weird problem with cookies crucial to keep user logged in are set to be session only (even after checking keep me logged in option), for just one session after logging in everything works fine. All settings seems to be same as yours. I was wondering if you had the same problem and if so how to solve this?

    Thanks in advance

  2. Hi,

    Haven’t really thought about that since it’s a desktop application. So every time the user runs my application I want them to authenticate. How ever in my example I use the standard webbrowser control included in .Net and that caches just like IE would do. So the next time I run the application and send the user to the auth screen it will just flash by and I get the token back.

    However this login flow is on a session basis. So if you need to keep the token alive for doing stuff in the background you might not be able to do that. In the past you could request an offline token that could be renewed at any time by your server or application to be able to access the API even if the user ended the session. I’m not sure if that is possible any more at least not with this login flow.

    You can read more about different tokens here: https://developers.facebook.com/docs/facebook-login/access-tokens

    /K

  3. I am getting this:

    You are not logged in: You are not logged in. Please log in and try again.

  4. I think this API has been retired ;(

  5. Have you created an app ID in the dev console?

  6. Yes I have. My app ID is ‘477253152474540’.

    I have also tried the following code samples:

    This one works great but is browser based and requires Facebook JS SDK
    http://blog.shakainteractive.com/fblogin/

    This one is similar to yours (Using https://www.facebook.com/dialog/oauth?…) and it does not work either
    http://www.codeproject.com/Articles/380635/Csharp-Application-Integration-with-Facebook-Twitt

    Many thanks

  7. I found the solution to the problem. Nothing wrong with your code.

    Need to add this to Valid OAuth redirect URIs:
    https://www.facebook.com/connect/login_success.html

    Need to work on parsing the response contents though as its giving me errors.

    Many thanks

  8. Happy to hear it all worked out!

  9. Thank you so much for this.. I wrote my own version , but was getting a bit frustrated with it. ( I was trying to do it in a background thread so I only had to show the browser when required..so I could find out if the user was logged in etc but failed!). It’s been a real bonus being able to re-use yours and delete all my mine 🙂

    Only thing I added was to give an optional param to the ‘new’ called ‘rerequest’ ( I’m a VB coder sorry!) If set to true, it adds auth_type=rerequest to the auth logon URL.

    Without this , there is no way to re ask for a scope that was previously rejected,

    Thank you so much

    Rob

  10. I’m happy it helped! I will actually do a new implementation off this code in an upcoming project and I haven’t really reflected over the previously rejected scopes. You know why you are a VB coder? Because you can’t see sharp… 😉

  11. Hah, I can do C# , but I always end up going back to VB. Been doing it for too many years (20ish). ( Plus I have too many other languages I work with every day , means I always go back to what I am most comfortable with when I get a choice ) .
    I always get stick from C # coders though.. oh well, I’ll stay 2nd class 😛
    I’ll have a look out for the new version 🙂

  12. I started out as a basic programmer my self went through vb, several versions prior to .net. I fall back to it every now and then but juggling multiple languages the syntax in C#, java and python are more similar so it’s easier to stick to that. Thank you for taking the time to write a few comments, really enjoy getting the feedback!

  13. Hello there,
    We have been developing a WPF application. Some users are encountering this problem at facebook login section. I am looking forward to your help at
    this point. Besides, those users who use any explorer version older than than Explorer 10 version cannot enter at all. Our most important problem right now
    is the one that I mentioned below.

    http://i.hizliresim.com/7vq4rv.jpg

    http://i.hizliresim.com/PM0gZQ.jpg

  14. Hi, as far as I can see the second one you get is a success message. The error message doesn’t say much since it’s not in English. Make sure you have the proper return url configured for the Facebook app in the dev console.

  15. After I login with my account, It thow an exception:
    “Sorry, something went wrong.
    We’re working on getting this fixed as soon as we can.”

  16. I would suspect that it has something to do with the return URI settings.

  17. Nice article, thanks!

    How do I download the code? the link points back to this page.

  18. The download link is dependent on javascript. Tested the link and it worked. Just to make it easier I put the code on Github as well. https://github.com/kallsbo/Facebook-API-login-flow-for-desktop-application

  19. how can i log in with different accounts, after the first time the app logs in with my personal account, please help me!

  20. You need to clear the cookies from the web browser control in order to get a “fresh” login page. If not the cookie will be sent to Facebook and it will just send the oauth token back since you have a valid session. Here you can read more about clearing cookies: https://social.msdn.microsoft.com/Forums/vstudio/en-US/2871993e-744e-46cf-8adc-63c60018637c/deleting-cookies-in-wpf-web-browser-control?forum=wpf


Leave a Reply

No trackbacks yet.