Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving users Facebook email on OWIN login [duplicate]

I am learning how to work with OWIN external auth using the default MVC template in VS 2015. I enabled Facebook auth and added the scope "email", expecting the user's email to be returned by Facebook after the user is authenticated (according to this). Still, there is no email in the context.User JSON object and context.Email is also null.

This is the relevant code in Startup.Auth.cs

var facebookOptions = new FacebookAuthenticationOptions
        {
            AppId = "XXXXXX",
            AppSecret = "XXXXXX",
            Provider = new FacebookAuthenticationProvider
            {
                OnAuthenticated =  context =>
                {
                    // Retrieve the OAuth access token to store for subsequent API calls
                    var accessToken = context.AccessToken;

                    // Retrieve the username
                    var facebookUserName = context.UserName;

                    // WHY IS IT EMPTY?
                    var facebookEmail = context.Email;

                    // You can even retrieve the full JSON-serialized user
                    var serializedUser = context.User;

                    return Task.FromResult(0);
                }
            }
        };

        facebookOptions.Scope.Add("email");

        app.UseFacebookAuthentication(facebookOptions);

Any ideas what is missing? Why is the facebook email address not being returned?

like image 421
Andrey Avatar asked Sep 26 '22 21:09

Andrey


1 Answers

Turns out there has been a breaking change in Facebook API v 2.4 where you have to specify fields you want to retrieve. The graph request used to be:

https://graph.facebook.com/v2.3/me?access_token=XXXXX

but for performance reasons as of FB API v2.4 you also have to specify fileds you want to retrieve within the scope:

https://graph.facebook.com/v2.4/me?fields=id,name,email&access_token=XXXXX

Microsoft FB client implementation by default attaches access_token to the query string as "?access_token" which leads to the broken request (extra question mark ):

https://graph.facebook.com/v2.4/me?fields=id,name,email?access_token=XXXXX

So, to remedy that we need to use a custom BackchannelHttpHandler. First, we create the endpoint class:

    public class FacebookBackChannelHandler : HttpClientHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (!request.RequestUri.AbsolutePath.Contains("/oauth"))
            {
                request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.Replace("?access_token", "&access_token"));
            }

            return await base.SendAsync(request, cancellationToken);
        }
    }

And then we provide it in facebook auth options along with explicitly specifying UserInformationEndpoint:

var facebookAuthOptions = new FacebookAuthenticationOptions
        {
            AppId = ConfigurationManager.AppSettings["FacebookAppId"],
            AppSecret = ConfigurationManager.AppSettings["FacebookAppSecret"],
            BackchannelHttpHandler = new FacebookBackChannelHandler(),
            UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=id,name,email",
            Scope = { "email" }
            <.....>
        };

From: https://stackoverflow.com/a/32636149/3130094

like image 172
Andrey Avatar answered Sep 29 '22 03:09

Andrey