Using Facebook Login with ASP.NET MVC 4

Login with Facebook is a very common feature that you will come across on the registration/login page on almost all good websites. ASP.NET MVC 4 includes support for OAuth and OpenID providers. Using these providers, you can let users log into your site using their existing credentials from Facebook, Twitter, Microsoft, and Google.

MVC 4 – Starter Template

This image shows the Login page from the Starter Site template, where a user can choose a Facebook, Twitter, Google or Microsoft icon to enable logging in with an external account:

img - starter template

However, In this blog post we will only be discussing about Facebook for Login.

Register your Website with Facebook

To authenticate users with their Facebook credentials, you must register your website with the Facebook. Head to developers.facebook.com and in the menu bar select App > Create a New App. You will be greeted with the below screen and a captcha. Once done you will be redirected to your App page.

img - create a new app

Your Facebook App Page

img - facebook app page Once you website’s Facebook App page is setup. Now you have you application’s App ID and App Secret keys. These values will be needed in your AuthConfig.cs file. If you open your AuthConfig.cs file you will find that the file contains code to register clients for external authentication providers. By default this code is commented out. For this tutorial, You must uncomment the code written for facebook, after uncommenting your AuthConfig.cs file should look like this.

public static class AuthConfig
{
    public static void RegisterAuth()
    {    
        //OAuthWebSecurity.RegisterMicrosoftClient(
        //    clientId: "",
        //    clientSecret: "");

        //OAuthWebSecurity.RegisterTwitterClient(
        //    consumerKey: "",
        //    consumerSecret: "");

        OAuthWebSecurity.RegisterFacebookClient(
            appId: "ENTER_KEY_FROM_YOUR_CREATED_FACEBOOK_APP_PAGE",
            appSecret: "ENTER_SECRET_KEY");

        //OAuthWebSecurity.RegisterGoogleClient();
    }
}

The appId and appSecret key values you will find in your Facebook App page.

First Test

Time to test a few things out now, run your application and go to the login page, Now you will the Facebook option under “Use another service to log in” header.

img - facebook first test

Click on that gives an error message, which says:

Given URL is not allowed by the Application configuration.: One or more of the given URLs is not allowed by the App’s settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App’s domains.

Now this is because we have not configured our Facebook App Page properly, go to your app page and in your settings. Add your localhost url along with the port number as shown below. Check out this stackoverflow thread for more info on this error.

img - facebook app settings change

Second Test

Now after making the above set of changes, lets again go to the login page and try logging in using Facebook, and voila !

enter image description here

In the above screenshot you can see the name I had specified while creating the app page “logintestbyyasser”. Press okay and continue. Now what happens when you click on the “Okay” button is interesting and is explained in the next section

ExternalLoginCallback

When the okay button is pressed control flows into ExternalLoginCallback action of the AccountController. The first line of this action says:

AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));

A lot of useful information can be retrieved from this result variable returned by the OAuthWebSecurity.VerifyAuthentication() method. Check the below screenshot of the debug values.

img - debug values

You could read values out from the result variable in the following manner. You should be able to access the basic user info like username, name, facebook link, gender and most important of all the accesstoken.

string username = result.UserName;

var id = result.ExtraData["id"];
var name = result.ExtraData["name"];
var link = result.ExtraData["link"];
var gender = result.ExtraData["gender"];
var accesstoken = result.ExtraData["accesstoken"];

Get user data from Facebook

You can get more user details by talking to facebook api using the facebook sdk. The easiest way is to download and install using the nuget download manager.

enter image description here

Once downloaded now you can use the following set of code to get user details using the userId fetched from the result variable.

var client = new FacebookClient();
dynamic me = client.Get(id);

The above line of code returns a json object as shown below, try this link – http://graph.facebook.com/790295720

{
    "id": "790295720",
    "first_name": "Yasser",
    "gender": "male",
    "last_name": "Shaikh",
    "link": "https://www.facebook.com/yrshaikh",
    "locale": "en_US",
    "middle_name": "Riaz",
    "name": "Yasser Riaz Shaikh",
    "username": "yrshaikh"
}

You can get a host of user details using the accesstoken as shown below :

var client = new FacebookClient(accesstoken);
dynamic me = client.Get("me");

In my example I was able to retrieve the below information for the logged in user (myprofile)

  • id
  • bio
  • education
  • favorite_athletes
  • favorite_teams
  • first_name
  • gender
  • hometown
  • last_name
  • link
  • location
  • locale
  • middle_name
  • name
  • sports
  • timezone
  • updated_time
  • username
  • verified
  • work

Get Email, More Permissions, Scope and other details

The above details we fetched were the basic details that you get, incase you want more details of the user like his email adress, pubish_stream or read_stream then it gets a little complicated. Thanks to Matheus Valiente Souza‘s answer to this stackoverflow thread, originally posted on this blog – Authenticating Facebook users with MVC 4 OAuth AND obtaining Scope Permissions!

You will need to create the following class – FacebookScopedClient, taken blindly from here – tested and it works!

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using DotNetOpenAuth.AspNet;
using Newtonsoft.Json;

namespace facebooklogintest.App_Start
{
    public class FacebookScopedClient : IAuthenticationClient
    {
        private string appId;
        private string appSecret;
        private string scope;

        private const string baseUrl = "https://www.facebook.com/dialog/oauth?client_id=";
        public const string graphApiToken = "https://graph.facebook.com/oauth/access_token?";
        public const string graphApiMe = "https://graph.facebook.com/me?";

        private static string GetHTML(string URL)
        {
            string connectionString = URL;

            try
            {
                System.Net.HttpWebRequest myRequest = (HttpWebRequest) WebRequest.Create(connectionString);
                myRequest.Credentials = CredentialCache.DefaultCredentials;
                //// Get the response
                WebResponse webResponse = myRequest.GetResponse();
                Stream respStream = webResponse.GetResponseStream();
                ////
                StreamReader ioStream = new StreamReader(respStream);
                string pageContent = ioStream.ReadToEnd();
                //// Close streams
                ioStream.Close();
                respStream.Close();
                return pageContent;
            }
            catch (Exception)
            {
            }
            return null;
        }

        private IDictionary<string, string> GetUserData(string accessCode, string redirectURI)
        {
            string token =
                GetHTML(graphApiToken + "client_id=" + appId + "&redirect_uri=" + HttpUtility.UrlEncode(redirectURI) +
                        "&client_secret=" + appSecret + "&code=" + accessCode);
            if (token == null || token == "")
            {
                return null;
            }
            string access_token = token.Substring(token.IndexOf("access_token="), token.IndexOf("&"));
            string data = GetHTML(graphApiMe + "fields=id,name,email,username,gender,link&" + access_token);

            // this dictionary must contains
            Dictionary<string, string> userData = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
            return userData;
        }

        public FacebookScopedClient(string appId, string appSecret, string scope)
        {
            this.appId = appId;
            this.appSecret = appSecret;
            this.scope = scope;
        }

        public string ProviderName
        {
            get { return "Facebook"; }
        }

        public void RequestAuthentication(System.Web.HttpContextBase context, Uri returnUrl)
        {
            string url = baseUrl + appId + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString()) + "&scope=" +
                         scope;
            context.Response.Redirect(url);
        }

        public AuthenticationResult VerifyAuthentication(System.Web.HttpContextBase context)
        {
            string code = context.Request.QueryString["code"];

            string rawUrl = context.Request.Url.OriginalString;
            //From this we need to remove code portion
            rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", "");

            IDictionary<string, string> userData = GetUserData(code, rawUrl);

            if (userData == null)
                return new AuthenticationResult(false, ProviderName, null, null, null);

            string id = userData["id"];
            string username = userData["username"];
            userData.Remove("id");
            userData.Remove("username");

            AuthenticationResult result = new AuthenticationResult(true, ProviderName, id, username, userData);
            return result;
        }
    }
} 

and then use this newly created class in your AuthConfig.cs like as shown below:

var facebooksocialData = new Dictionary<string, object>();
facebooksocialData.Add("scope", "email, publish_stream, read_stream");

OAuthWebSecurity.RegisterClient(new FacebookScopedClient(
    appId: "1376784812605727",
    appSecret: "ce379ea552bf423b6f8434da14c85f65",
    scope:"email, user_likes, friends_likes, user_birthday"),
    "Facebook",
    null
);

Important Note: For re-authenticating your facebook account with the app with new set of permissions, you may need to remove the existing set of permission and trying again.

And now when you try logging in using Facebook the following screen is shown, but this time more permissions are requested this includes friend list, email address, birthday and likes and your friend’s likes.

enter image description here

Now if you check again with the following code

string email =  result.ExtraData["email"];

Hope this help, please give your feedback/suggestions/correction using the comment box below. Thanks.

References