Login with Facebook in ASP.NET C# - Retrieve user details

johna by | March 23, 2012 | ASP.NET Web Forms SEO and Social Networking Web Development

I needed to add a login with Facebook button to a website and wanted a simple solution that would check whether the user successfully logged in and return their email address and name. I considered using the C# SDK but couldn't find much in the way of documentation or samples to accomplish this task.

The Computer Outpost is an Australian-based online automotive book shop specialising in car workshop manuals and books.

We first need the usual Facebook JavaScript code to load the Facebook JavaScript API, and then we need to subscribe to an event so that we can redirect to a page where we can capture the user's details.
<div id="fb-root"></div>
<script src="http://connect.facebook.net/en_US/all.js"></script>
<script>
FB.init({ appId: '000', status: true,
cookie: true, xfbml: true, oauth: true
});
</script>

The following code creates the Facebook log in button, and redirects them to my Facebook server side code to log in the user.
<fb:login-button scope="email" onlogin="window.location.href='/FB.aspx?dest=<%= Server.UrlEncode(Request.Url.PathAndQuery) %>';">Login with Facebook</fb:login-button>

If the user logged in by Facebook then I want them logged out of my site of they log out if Facebook, so I put the following code in a PlaceHolder control and only show it if they did log in with Facebook. Inside this PlaceHolder is a logout button (you would need to add a server side event to handle logging out the user), and when the Facebook logout event occurs it triggers a click of your logout button.
<asp:PlaceHolder ID="plhLogout" runat="server" Visible="false">
<asp:Button ID="btnLogout" runat="server" OnClick="btnLogout_Click" Text="Logout">
<script type="text/javascript">
FB.Event.subscribe('auth.logout', function (response) {
__doPostBack("<%= btnLogout.UniqueID %>", "");
});
</script>
</asp:PlaceHolder>

The Facebook App ID and App Secret need to be stored in the web.config file.
<add key="FacebookAppId" value="000"/>
<add key="FacebookAppSecret" value="abc000"/>

The following code is FacebookLogin.cs which contains a class for storing user information (FacebookUser) and the necessary code to retrieve the user's details.
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Script.Serialization;

namespace MyWebsite
{
public class FacebookLogin
{
protected static string _appId = null;
protected static string AppId
{
get
{
if (_appId == null)
_appId = ConfigurationManager.AppSettings["FacebookAppId"] ?? null;
return _appId;
}
}

protected static string _appSecret = null;
protected static string AppSecret
{
get
{
if (_appSecret == null)
_appSecret = ConfigurationManager.AppSettings["FacebookAppSecret"] ?? null;
return _appSecret;
}
}

public static FacebookUser CheckLogin()
{
if (HttpContext.Current.Request.Cookies["fbsr_" + AppId] == null)
{
return null;
}

string fbsr = HttpContext.Current.Request.Cookies["fbsr_" + AppId].Value ?? string.Empty;

int separator = fbsr.IndexOf(".");
if (separator == -1)
{
return null;
}

string encodedSig = fbsr.Substring(0, separator);
string payload = fbsr.Substring(separator + 1);

string sig = Base64Decode(encodedSig);

var serializer = new JavaScriptSerializer();
Dictionary<string, string> data = serializer.Deserialize<Dictionary<string, string>>(Base64Decode(payload));

if (data["algorithm"].ToUpper() != "HMAC-SHA256")
{
return null;
}

HMACSHA256 crypt = new HMACSHA256(Encoding.ASCII.GetBytes(AppSecret));
crypt.ComputeHash(Encoding.UTF8.GetBytes(payload));
string expectedSig = Encoding.UTF8.GetString(crypt.Hash);

if (sig != expectedSig)
{
return null;
}

string accessTokenResponse = FileGetContents("https://graph.facebook.com/oauth/access_token?client_id=" + AppId + "&redirect_uri=&client_secret=" + AppSecret + "&code=" + data["code"]);
NameValueCollection options = HttpUtility.ParseQueryString(accessTokenResponse);

string userResponse = FileGetContents("https://graph.facebook.com/me?access_token=" + options["access_token"]);

userResponse = Regex.Replace(userResponse, @"u([dA-Fa-f]{4})", v => ((char)Convert.ToInt32(v.Groups[1].Value, 16)).ToString());

FacebookUser user = new FacebookUser();

Regex getValues = new Regex("(?<="email":")(.+?)(?=")");
Match infoMatch = getValues.Match(userResponse);
user.Email = infoMatch.Value;

getValues = new Regex("(?<="first_name":")(.+?)(?=")");
infoMatch = getValues.Match(userResponse);
user.FirstName = infoMatch.Value;

getValues = new Regex("(?<="last_name":")(.+?)(?=")");
infoMatch = getValues.Match(userResponse);
user.LastName = infoMatch.Value;

return user;
}

protected static string FileGetContents(string url)
{
string result;
WebResponse response;
WebRequest request = HttpWebRequest.Create(url);
response = request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
result = sr.ReadToEnd();
sr.Close();
}
return result;
}

protected static string Base64Decode(string input)
{
UTF8Encoding encoding = new UTF8Encoding();
string encoded = input.Replace("=", string.Empty).Replace('-', '+').Replace('_', '/');
var decoded = Convert.FromBase64String(encoded.PadRight(encoded.Length + (4 - encoded.Length % 4) % 4, '='));
var result = encoding.GetString(decoded);
return result;
}
}

public class FacebookUser
{
public string UID { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}

Then on the page we redirect to upon login (in this case FB.aspx) we can check that the user logged in and retrieve their email address and first name.
FacebookUser user = FacebookLogin.CheckLogin();
if (user != null)
{
Response.Write("<p>" + user.Email);
Response.Write("<p>" + user.FirstName);
Response.Write("<p>" + user.LastName);
}

Related Posts

Web Development

How to set up a debugging using the Turnkey Linux LAMP stack and VS Code

by johna | December 19, 2023
The second part in my guide to setting up a website and database using the Turnkey Linux LAMP stack.

Website Hosting Web Development

How to set up a website and database using the Turnkey Linux LAMP stack

by johna | November 18, 2023
If you need to host your own website for the purposes of web development, Turnkey Linux LAMP Stack is an easy to install all-in-one solution that you can set up on a spare computer or a VM (Virtual Machine).

Web Development

Intermittent "Unable to read data from the transport connection: net_io_connectionclosed" errors

by johna | May 6, 2020
If you are having intermittent problems sending email in .NET using System.Net.Mail consider switching libraries.

Comments

Ikram Shams

by Ikram Shams | April 28, 2012

Thanks for a good article. It is working well but if the user is already log in into his facebook acccount then it is not working. I think something should be added into the java script code.

Please suggest me.

Reply

John Avis

by John Avis | April 28, 2012

If the user is already logged in with Facebook then when they click your Facebook log in button they should log in straight away without being requested for password.

I also updated the code a little to handle logging out better.

Reply

Ikram Shams

by Ikram Shams | April 29, 2012

Thanks, it is working fine but if a user click on "Login with FaceBook" then after coming Login window of Facebook he cancels it.In this situation it is giving me a error. The error details is:

Object reference not set to an instance of an object.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error:


Line 42: {
Line 43:
Line 44: string fbsr = HttpContext.Current.Request.Cookies["fbsr_" + AppId].Value;
Line 45:
Line 46: int separator = fbsr.IndexOf(".");

Source File: d:\IkramShams_Project\Company_Website\Website\AJPWebsite\App_Code\FacebookLogin.cs Line: 44

Reply

John Avis

by John Avis | April 30, 2012

I see the problem and have updated the source. There was no protection against the cookie not existing. You need to change line 44 to:

string fbsr = HttpContext.Current.Request.Cookies["fbsr_" + AppId] == null ? string.Empty : HttpContext.Current.Request.Cookies["fbsr_" + AppId].Value;

Reply

by luciano castro | May 16, 2012

tks a lot, was looking for this explanation to 4 weeks

Reply

sheik dawood

by sheik dawood | May 24, 2012

FB login integration in 5 minutes. Thank you very much

Reply

Vincent AUGEROT

by Vincent AUGEROT | May 31, 2012

Thank you very much for this very great tutorial !It takes me only 5 minutes to successfully add Facebook connector to my website !

Reply

Phil

by Phil | June 22, 2012

Am I missing something, I've been going round in circles with this facebook login for days now. It seems relatively straight forward getting the logged in users details on the client but I'm having a nightmare with the server side flow. I have tried your method (after converting to VB.net) but HttpContext.Current.Request.Cookies("fbsr_" + AppId) is always null? As far as I can see I've done everything exactly the same...

Any help would be much appreciated.

Reply

John Avis

by John Avis | June 22, 2012

Are you replacing all the zeros in the Facebook JavaScript API load and the web.config with your Facebook Application ID and Application Secret (which you can create at the Facebook Developer site)?

Reply

by prasad | June 18, 2013

string fbsr = HttpContext.Current.Request.Cookies["fbsr_" + AppId] == null ? string.Empty : HttpContext.Current.Request.Cookies["fbsr_" + AppId].Value;

with this am getting problem in ie8

Reply

John Avis

by John Avis | June 18, 2013

Hi prasad. Can you give details about what error you are getting and more information so we can help you?

Reply

Leave a Reply

by prasad | June 19, 2013

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
every time it returns null only

Reply

John Avis

by John Avis | June 19, 2013

prasad: Can you debug to see what is null?

Reply

by prasad | June 19, 2013

int separator = fbsr.IndexOf(".");
it returns -1 every time

Reply

John Avis

by John Avis | June 19, 2013

@prasad: I updated CheckLogin() as there was inadequate checking for a cookie value, please try the updated code.

Reply

by prasad | June 20, 2013

if i add this code am getting this error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS0246: The type or namespace name 'FacebookUser' could not be found (are you missing a using directive or an assembly reference?)

can u update fb.aspx page?

Reply

John Avis

by John Avis | June 20, 2013

prasad: See the line in the code for FacebookLogin.cs "namespace MyWebsite"? You are going to have to change the namespace to match the namespace used in your web application, or remove it if you have a website (not application) without a namespace.

Reply

by prasad | June 20, 2013

HttpContext.Current.Request.Cookies["fbsr_" + AppId]
still am getting nothing in this line.
it is working fine in ie9,ie10,chrome but not working in ie8

Reply

John Avis

by John Avis | June 20, 2013

prasad: I just Google-ed problems with Facebook login in IE8 and there are several common problems. Have you tried restoring your privacy settings in IE8 to default? Also, add the Facebook XMLS namespace to your HTML declaration like this: <html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">

Reply

prasad

by prasad | June 20, 2013

I added <html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml"> event though it is not working.
if u find any solution pls give me reply
thanks a lot John

Reply

Urvi Patel

by Urvi Patel | October 3, 2013

hi,
In my page Regex getValues = new Regex("(?<="email":")(.+?)(?=")");
is giving error:Envalid expresssion.

Reply

John Avis

by John Avis | October 3, 2013

Hi Urvi. There was a problem with the way code was appearing in my blog. I have fixed it now, so please copy and paste again. Thanks.

Reply

Urvi Patel

by Urvi Patel | October 3, 2013

Hi,thanks for reply.
But now sometimes i getting error:(400) Bad Request
on Line response = request.GetResponse();
And also unble to logout.

Reply

John Avis

by John Avis | October 3, 2013

Not sure about the 400 error, but the logout issue might be due to some extra coding you need to do. When the user logs out of Facebook my code simulates the click of an ASP.NET logout button (which you need to add and handle server side click event). I have updated my code a little, but you will need to adapt this to your requirements.

Reply

Nic

by Nic | June 5, 2014

is there a link to download the source
as the code is mess up with the html
thank a lot

Reply

John Avis

by John Avis | June 5, 2014

Sorry, no, there's no code download as it is not a complete project. You will need to copy and paste all of the code blocks from this article and integrate into your own project and modify as necessary.

Reply

About

...random postings about web development and programming, Internet, computers and electronics topics.

I recommend ASPnix for web hosting and Crazy Domains for domain registration.

Subscribe

Get the latest posts delivered to your inbox.