23

With v2.3 of the Facebook API, provided the following was set, the users email address would be returned on the callback to ExternalLoginCallback;

app.UseFacebookAuthentication(new FacebookAuthenticationOptions
{
    AppId = "XXX",
    AppSecret = "XXX",
    Scope = { "email" }
});

However, any app that can only target v2.4 (released 8 July) no longer returns the email address to the ExternalLoginCallback.

I think this may possibly be related to the v2.4 changes as listed here;

Declarative Fields

To try to improve performance on mobile networks, Nodes and Edges in v2.4 requires that you explicitly request the field(s) you need for your GET requests. For example, GET /v2.4/me/feed no longer includes likes and comments by default, but GET /v2.4/me/feed?fields=comments,likes will return the data. For more details see the docs on how to request specific fields.

How can I access this email address now?

Stafford Williams
  • 9,696
  • 8
  • 50
  • 101

2 Answers2

57

To resolve this I had to install the Facebook SDK for .NET from nuget and query the email address separately.

In the ExternalLoginCallback method, I added a conditional to populate the email address from the Facebook Graph API;

var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();

if (loginInfo == null)
{
    return RedirectToAction("Login");
}

// added the following lines
if (loginInfo.Login.LoginProvider == "Facebook")
{
    var identity = AuthenticationManager.GetExternalIdentity(DefaultAuthenticationTypes.ExternalCookie);
    var access_token = identity.FindFirstValue("FacebookAccessToken");
    var fb = new FacebookClient(access_token);
    dynamic myInfo = fb.Get("/me?fields=email"); // specify the email field
    loginInfo.Email = myInfo.email;
}

And to get the FacebookAccessToken I extended ConfigureAuth;

app.UseFacebookAuthentication(new FacebookAuthenticationOptions
{
    AppId = "XXX",
    AppSecret = "XXX",
    Scope = { "email" },
    Provider = new FacebookAuthenticationProvider
    {
        OnAuthenticated = context =>
        {
            context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
            return Task.FromResult(true);
        }
    }
});
Michal Hosala
  • 5,570
  • 1
  • 22
  • 49
Stafford Williams
  • 9,696
  • 8
  • 50
  • 101
  • Hi, what is the name of that Facebook library nuget that you used? I would love to know. thanks. – Yovav Aug 10 '15 at 01:52
  • Great! it worked. now I'm trying to get other values user_birthday - any idea how to do that? – Yovav Aug 10 '15 at 02:17
  • 4
    @Yovav check out [the api](https://developers.facebook.com/docs/graph-api/reference/user). It says you have to list all the fields you want back, so I guess if you changed the request to `/me?fields=email,birthday` you'd get the email and the birthday in the response. – Stafford Williams Aug 10 '15 at 03:08
  • Thank you @StaffordWilliams. I scoured the web to find this! – Jorge Rodrigues dos Santos Sep 05 '15 at 17:31
  • Very useful hack, thanks a lot buddy! – Hajjat Nov 06 '15 at 06:14
  • Thanks a lot @StaffordWilliams – Nisar Jan 06 '16 at 13:32
  • @StaffordWilliams Excellent explanation. Can you help me a little bit more. If I need more information what can I do? like whole name , phone number, friend list, etc etc etc... – 3 rules Sep 27 '16 at 12:09
  • 1
    I can confirm that this still works in 2017 as I am the first to comment this year :))) Using all the (almost) latest stuff too - vs 2015 Community, Asp.Net 4.6.1 – Andy Jan 02 '17 at 18:24
  • Hello, at dynamic myInfo = fb.Get("/me?fields=email"); I get following error: (GraphMethodException - #100) API calls from the server require an appsecret_proof argument – Luke Jun 28 '17 at 17:39
  • Very Helpful, Thanks buddy! – Vel Sep 12 '17 at 10:28
  • Nov 2017 - loginInfo is always null - so your example doesn't work - this is with a vanilla MVC sample project. Is this due to API changes - how to fix? – niico Nov 12 '17 at 16:15
14

In MVC 6 (Asp.net Core 1.0), by configuring FacebookAuthentication in startup.cs like this:

         app.UseFacebookAuthentication(options =>
            {
                options.AppId = Configuration["Authentication:Facebook:AppId"];
                options.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
                options.Scope.Add("email");
                options.UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=id,name,email,first_name,last_name";
            });

I could get the email. I.e:

   var info = await _signInManager.GetExternalLoginInfoAsync();
   var email = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Email);
Ole Kristian Losvik
  • 1,133
  • 3
  • 20
  • 32