Tuesday, May 13, 2014

ASP.NET authentication with Facebook, LinkedIn and Google

How to make possible to authenticate with some of social network ID (such as Google authentication, facebook login and LinkedIn) to your ASP.NET web form application?


Use Visual Studio 2013 built in functionality

One possibility is to use Visual Studio 2013 built in functionality inside ASP .NET Web Form Site template (it is not only template with built in authentication). You need to configure project to work with social networks logins.

To learn more how to configure Visual Studio 2013 to work with external social sites visit: External authentication services c# and Logging In Using External Sites in an ASP.NET Web Pages.


    Why I do not like VS built in authentication inside templates

  • I find it difficult to understand and change to my application needs

  • do not know what happens under the hood, for example in ASP .NET Web Form Site template, attached database is created with tables for storing data about users, I do not know when this database is created and do not know how methods exactly work

  • connecting to external social networks is relatively new and have bugs

  • so if you want to use proposed model go with it, but if you have some specific ideas maybe it is good idea to start from scratch

How Asp.NET logging communicate with Facebook

This is simplified and User agent is not taken into account
  • ASP.NET site sends facebook Application ID and URL of ASP.NET application to facebook
    (https://graph.facebook.com/oauth/authorize?client_id=[ApplicationID]&redirect_uri=[ASP.NET_ADDRESS])

  • user is redirected to facebook site where he need to login with his facebook login

  • facebook authorization page is redirected to ASP.NET authorization page, inside URL is "code" query parameter

  • ASP.NET read code parameter and send web request to facebook with ApplicationID, Application secret and code which is received two steps before

  • ASP.NET get response from facebook site, now ASP.NET have a token

  • Now ASP.NET can send request to facebook site with token to get data about user


There is a code for authentication to your ASP.NET application with Facebook login.

  • Facebook button is first clicked

  • when facebook page redirect back to ASP.NET page GetAuthToken method is called and then GetUserInfo method is called

  • inside GetUserInfo method ASP.NET get id of facebook user and user facebook name

  • you must create facebook application to get APP_KEY and APP_SECRET, find more about it here

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.IO;
using Newtonsoft.Json.Linq;
using System.Net;

public partial class JustFacebook : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {       
        if (Request.Url.AbsolutePath.IndexOf("/OnFacebookAuth") > 0 && !string.IsNullOrEmpty(Request.Params["code"]))
        {          
            GetAuthToken();
            GetUserInfoAction();
        }

    }

    protected void btnFacebookLogin_Click(object sender, EventArgs e)
    {
        string redirectTo = Request.Url.Scheme + "://" + Request.Url.Authority + Request.Url.AbsolutePath + "/OnFacebookAuth";
        string request = string.Format("https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}", "APP_KEY", redirectTo);
        Response.Redirect(request);
    }

    private void GetAuthToken()
    {
        string redirectTo = Request.Url.Scheme + "://" + Request.Url.Authority + Request.Url.AbsolutePath;
        string code = Request.Params["code"];
        string facebookApplicationSecret = "APP_SECRET";
        string request = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}", APP_KEY, redirectTo,facebookApplicationSecret, code);

        var httpRequest = (HttpWebRequest)WebRequest.Create(request);
        var httpResponse = (HttpWebResponse)httpRequest.GetResponse();

        Encoding enc = Encoding.UTF8;
        var loResponseStream = new StreamReader(httpResponse.GetResponseStream(), enc);
        string response = loResponseStream.ReadToEnd();
        try
        {
            string[] pairResponse = response.Split('&');
            string accessToken = pairResponse[0].Split('=')[1];
            Session["FacebookAccessTokenSession"] = accessToken;
        }
        catch
        {
            throw;
        }
    }

    private void GetUserInfoAction()
    {
        if (Session["FacebookAccessTokenSession"] != null)
        {
            object token = Session["FacebookAccessTokenSession"];
            string request = string.Format("https://graph.facebook.com/me?access_token={0}", token);
            var httpRequest = (HttpWebRequest)WebRequest.Create(request);
            var httpResponse = (HttpWebResponse)httpRequest.GetResponse();

            Encoding enc = Encoding.UTF8;
            var loResponseStream = new StreamReader(httpResponse.GetResponseStream(), enc);

            string response = loResponseStream.ReadToEnd();
            JObject jsonObject = JObject.Parse(response);

            var id = (string)jsonObject["link"];
            var displayName = (string)jsonObject["name"];
        }
    }
}


Simplest way to authenticate using external social network logins

Some good people make various classes to make easier to login using Facebook, Google authenticate, LinkedIn and others. Those classes hides complexity of communicating with LogIn services.

I find ASPSnippets very handy and easy for use. There is simple step by step tutorial for:


Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using ASPSnippets.LinkedInAPI;
using ASPSnippets.FaceBookAPI;
using System.Web.Script.Serialization;
using System.Data;

public partial class JustASPSnippets : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        FaceBookConnect.API_Key = FACEBOOK_KEY;
        FaceBookConnect.API_Secret = FACEBOOK_SECRET;
        if (!string.IsNullOrEmpty(Request.Params["code"]) && Session["SocialNetworkCalled"] == "Facebook")
        {
            string code = Request.QueryString["code"];
            string data = FaceBookConnect.Fetch(code, "me");
            FaceBookUser faceBookUser = new JavaScriptSerializer().Deserialize<FaceBookUser>(data);

            string id = faceBookUser.Id;
            string userName = faceBookUser.UserName;
            string name = faceBookUser.Name;
            string email = faceBookUser.Email;
        }

        LinkedInConnect.APIKey = LINKEDIN_KEY;
        LinkedInConnect.APISecret = LINKEDIN_SECRET;
        LinkedInConnect.RedirectUrl = Request.Url.AbsoluteUri.Split('?')[0];
        if (LinkedInConnect.IsAuthorized && Session["SocialNetworkCalled"] == "LinkedIn")
        {
            DataSet ds = LinkedInConnect.Fetch();
            string a = ds.Tables["person"].Rows[0]["first-name"].ToString();
            string b = a + " " + ds.Tables["person"].Rows[0]["last-name"].ToString();
            string email = ds.Tables["person"].Rows[0]["email-address"].ToString();
            string linkeinemail = ds.Tables["person"].Rows[0]["id"].ToString();
        }
        
        Session["SocialNetworkCalled"] = "";

    }

    protected void btn_FacebookLogin_Click(object sender, EventArgs e)
    {
        Session["SocialNetworkCalled"] = "Facebook";
        FaceBookConnect.Authorize("email,user_birthday", Request.Url.AbsoluteUri.Split('?')[0]);
    }

    protected void btn_LinkedInLogin_Click(object sender, EventArgs e)
    {
        Session["SocialNetworkCalled"] = "LinkedIn";
        LinkedInConnect.Authorize();    
    }
}

FaceBookUser class:

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for Facebook
/// </summary>
public class FaceBookUser
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string UserName { get; set; }
    public string PictureUrl { get; set; }
    public string Email { get; set; }
    public string Birthday { get; set; }
    public string Gender { get; set; }
    public FaceBookEntity Location { get; set; }
}

public class FaceBookEntity
{
    public string Id { get; set; }
    public string Name { get; set; }
}

Let's try explain code in few lines:


  • when btn_FacebookLogin is clicked, FaceBookConnect.Authorize method is called, it redirect user to facebook login page

  • if user successfully login to facebook, he is redirected back to ASP.NET application Login page

  • then inside Page_Load it is recognized ASP.NET page is loaded after facebook login page

  • FaceBookConnect.Fetch method is called and ASP.NET application can get data about user

  • with LinkedIn authentication is similar process

A few more things

Be careful with Google OpenId identifier because it change if you change domain.


No comments: