ASP.NET Core Facebook Authentication Middleware user picture - facebook

I'm trying to retrieve user profile picture with Facebook Authentication middleware in ASP.NET Core 1.0. I have managed to add these configurations to make the user picture availble
app.UseFacebookAuthentication(new FacebookOptions()
{
AppId = Configuration["Authentication:Facebook:AppId"],
AppSecret = Configuration["Authentication:Facebook:AppSecret"],
Scope = { "public_profile" },
Fields = { "picture" }
});
and to retrieve data
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
and
var userName = info.Principal.FindFirstValue(ClaimTypes.GivenName);
But How can I now retrieve user picture as there is not Claim Type for it?

As Set said in his answer you can get the picture using the Facebook Graph API like this https://graph.facebook.com/{user-id}/picture.
Example code :
var info = await _signInManager.GetExternalLoginInfoAsync();
var identifier = info.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
var picture = $"https://graph.facebook.com/{identifier}/picture";
You might want to check if info is not null and if info.LoginProvider is facebook.

Yes, in general, the standard (oauth) implementation of UserInfo Endpoint may return picture in response if you specify Fields = { "picture" }.
Facebook Graph API provides https://graph.facebook.com/v2.6/me as UserInformation endpoint and ASP.NET Core Facebook Auth Middleware uses it for claims population.
The problem is that Facebook Graph API doesn't return picture in response if you use this \me endpoint. They did so before but for some reason have removed that. Related SO: facebook oauth, no picture with basic permissions
But you can get the picture using:
https://graph.facebook.com/USERNAME/picture

In my project ASP.NET Core 2.2 I use this code:
services.AddAuthentication()
.AddFacebook(options =>
{
options.AppId = Configuration["Authentication:Facebook:AppId"];
options.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
options.Events.OnCreatingTicket = (context) =>
{
var picture = $"https://graph.facebook.com/{context.Principal.FindFirstValue(ClaimTypes.NameIdentifier)}/picture?type=large";
context.Identity.AddClaim(new Claim("Picture", picture));
return Task.CompletedTask;
};
});
And in Controller, in ExternalLoginCallback action I retrieve value this way:
var info = await _signInManager.GetExternalLoginInfoAsync();
var picture = info.Principal.FindFirstValue("Picture");

Related

.net core 2.0 external login - extra profile information

I have a .net core 2.0 app and am implementing external login providers like google, twitter, and facebook. I have the requirement to get the user's display name and profile picture, and can't find any documentaion of how to achieve this in .net core 2.0.
I add the authentication like this post: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/
Here are my twitter login and callback functions...
[HttpGet]
[Route("/api/security/login/type/socialmedia/twitter")]
public IActionResult GetTwitterLogin(string redirect_uri)
{
ClientCallback = redirect_uri;
string redirectUrl = "/api/security/login/type/socialmedia/twittercallback";
var properties = SignInManager.ConfigureExternalAuthenticationProperties("Twitter", redirectUrl);
return Challenge(properties, "Twitter");
}
[HttpGet]
[Route("/api/security/login/type/socialmedia/twittercallback")]
public async Task<HttpResponseMessage> GetTwitterCallBackAsync()
{
var info = await SignInManager.GetExternalLoginInfoAsync();
var result = await SignInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
if (result.Succeeded)
{
}
else
{
}
Response.StatusCode = (int)HttpStatusCode.OK;
return null;
}
It looks like you can get some items from info.Principal.Claims, but nothing for the user's display name or profile picture.
How do you get the display name or profile picture for the various login providers?
I finally figured this out...you need to add claims when you configure the authentication. These claims look at the resulting json response and pulls items from it. The pertinent lines are the ClaimActions items.
services.AddAuthentication()
.AddTwitter(twitterOptions =>
{
twitterOptions.ConsumerKey = cfg.SystemConfig["TwitterConsumerKey"];
twitterOptions.ConsumerSecret = cfg.SystemConfig["TwitterConsumerSecret"];
twitterOptions.SaveTokens = true;
twitterOptions.RetrieveUserDetails = true;
twitterOptions.ClaimActions.MapJsonKey("display-name", "name");
twitterOptions.ClaimActions.MapJsonKey("profile-image-url", "profile_image_url_https");
})
.AddFacebook(facebookOptions =>
{
facebookOptions.AppId = cfg.SystemConfig["FacebookClientId"];
facebookOptions.AppSecret = cfg.SystemConfig["FacebookClientSecret"];
facebookOptions.SaveTokens = true;
facebookOptions.ClaimActions.MapJsonKey("display-name", "name");
})
.AddGoogle(googleOptions =>
{
googleOptions.ClientId = cfg.SystemConfig["GoogleClientId"];
googleOptions.ClientSecret = cfg.SystemConfig["GoogleClientSecret"];
googleOptions.SaveTokens = true;
googleOptions.ClaimActions.MapJsonSubKey("profile-image-url", "image", "url");
googleOptions.ClaimActions.MapJsonKey("display-name", "displayName" );
});
After getting the login information in your callback using
var info = await SignInManager.GetExternalLoginInfoAsync();
If populated successfully you can query the claims and find the values
var profileImageClaim = info.Principal.Claims.Where(x => x.Type == "profile-image-url").FirstOrDefault();
Facebook images are different from google and twitter and can be found using...
var claim = info.Principal.Claims.Where(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier").FirstOrDefault();
var url = "http://graph.facebook.com/" + claim.Value + "/picture";
In ASP.NET Core 2.0, FacebookOptions uses extension methods on ClaimActions to map the profile data returned by UserInformationEndpoint.
ClaimActions.MapJsonKey(ClaimTypes.DateOfBirth, "birthday");
In the mapping above, "birthday" is a top-level property in the Facebook Graph API response that's mapped to the value represented by the claim ClaimTypes.DateOfBirth.
To grab the profile picture you would do the same thing, but since the picture in the Graph API response is a nested JSON object, you would have to use MapCustomJson()
services.AddAuthentication()
.AddFacebook(options =>
{
// ...other options omitted
options.Fields.Add("picture");
options.ClaimActions.MapCustomJson("urn:facebook:picture",
claim => (string)claim.SelectToken("picture.data.url"));
})
Here, claim is a NewtonSoft JObject that uses JPath syntax to select the nested property value and cast it to a string.
The profile picture URL will now appear in your Claims list.

Azure Mobile Services backend serviceUser does not return Facebook identities as expected

I'm struggling with a Xamarin Forms (iOS)/Azure Mobile Services/Facebook issue that I don't know how to resolve. What I'm trying to do is login to Facebook using AMS and then save that user's details to a service side database via a custom controller. I am running Azure Mobile Services on the backend.
What I have in place is the code below that successfully logs in a Facebook user.
var fbUser = await DependencyService.Get<IMobileClient>().LoginAsync(MobileServiceAuthenticationProvider.Facebook);
I then want to save fbUser to the database where I'm using ASP.NET Identity tables all configured. I want to use this user to gain access to the facebook user's profile information. I therefore have a backend service custom controller action that looks like this:
[Route("logintofacebook")]
[AuthorizeLevel(AuthorizationLevel.Anonymous)]
public async Task<IHttpActionResult> LoginToFacebook(MobileServiceUser msUser)
{
try
{
if (msUser != null)
{
var serviceUser = User as ServiceUser;
var identities = await serviceUser.GetIdentitiesAsync();
var result = new JObject();
var fb = identities.OfType<FacebookCredentials>().FirstOrDefault();
if (fb == null)
{
return NotFound();
}
var googleCredentials = identities.OfType<GoogleCredentials>().FirstOrDefault();
var azure = identities.OfType<MicrosoftAccountCredentials>().FirstOrDefault();
var accessToken = fb.AccessToken;
result.Add("facebook",
await GetProviderInfo("https://graph.facebook.com/me?access_token=" + accessToken));
var email = GetUserInfo(result);
var userTypeId = UTypes.Facebook;
When debugging on the backend side, the MobileServiceUser is a valid object and I can check the token and Facebook userid which are the same as were created on the client. However, the highlighted line returns zero identities. This means that fb variable end up being null.
The question is, why are no identities being returned from the serviceUser variable above?
Here's what the debugged AMS token looks like when debugged with jwt.io
{
"iss": "urn:microsoft:windows-azure:zumo",
"aud": "urn:microsoft:windows-azure:zumo",
"nbf": 1446872000,
"exp": 1449464000,
"urn:microsoft:credentials": "{\"accessToken\":\"CAAL2gwRM4RYBAKV9Wp0Evjp2aATnm5OIHHc15ujJfeevqCW6DoI36HOQCOYq96xUjZA6VXwovnkBOlY0SkC9nrdwr8jdbF3qJdtK4GAHVk9SGxKVYUZBJ4UwPqQmb5yka93GzL0Fl86m93LnqTffIPJ6vkMfpP0ZAroKzmcJxM1pJ7BAAAA\"}",
"uid": "Facebook:0000000000000000",
"ver": "2"
}
(I've replaced out the facebook section with zeros)
thanks
O

How to get Facebook Friend List in ASP.NET?

I'm building an App with ASP.NET MVC 5 and Identity.
So far the login is working correctly.
Here the auth:
var fb = new FacebookAuthenticationOptions();
fb.Scope.Add("email");
fb.Scope.Add("friends_about_me");
fb.Scope.Add("friends_photos");
fb.AppId = "";
fb.AppSecret = "";
fb.Provider = new FacebookAuthenticationProvider() {
OnAuthenticated = async FbContext => {
FbContext.Identity.AddClaim(
new System.Security.Claims.Claim("FacebookAccessToken", FbContext.AccessToken));
}
};
fb.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
app.UseFacebookAuthentication(fb);
I'm trying to get the friends list. I've been looking for a few examples but none is working with this version of MVC 5.
My question is. How can I fetch all the friends with this version?
I don't want to use Javascript API, I want all the code in c# and then send to the view.
I think I just need to rewrite the login and store the access token in the session, and then simply call var client = new FacebookClient(TOKEN);
So how can I rewrite the login?
You've already got everything you need. The OnAuthenticated callback you've set adds a claim containing the access token for Facebook. You just need to pull the claim for the user:
var identity = (ClaimsIdentity)User.Identity;
var facebookClaim = identity.Claims.FirstOrDefault(c => c.Type == "FacebookAccessToken");
if (facebookClaim != null)
{
// access facebook API with `facebookClaim.Value`
}
And if it exists, then you can use the Facebook API to pull in their friends by making standard HTTP calls via something like HttpClient.

Retriving Facebook posts from Profile via FB api

I have registered an app in facebook developers program and I can retrieve posts from facebook page using fb api, but I cannot retrieve posts from facebook profile. Should I use some different access token for both page or profile? Is there a different way for retrieving posts from facebook page and profile?
Any help will be appreciated!
You may need the user_status permission.
And you call the posts using this graph query {USER_ID}?fields=statuses
Prerequisite:- You need to have valida FB token for all the request:-
I am answering using c# language.
Step 1:- First you need to get the user's FB id using FB token
I am using Facebook SDK 7.0.6 for querying purpose
here's how to initialize the FB service which we will use in our consecutive calls.
FacebookService facebookService = new FacebookService(facebookToken);
var _facebookClient = new Facebook.FacebookClient(token);
Code snippet
public string GetFacebookID(string facebookToken)
{
dynamic result = _facebookClient.Get("me?fields=id");
if (result.ToString().Contains("id"))
{
return result["id"];
}
return string.Empty;
}
after that you can execute below method to get user's post using FB ID and token
public List<Post> GetPostsForUser(string facebookID)
{
List<Post> posts = new List<Post>();
dynamic result = _facebookClient.Get(facebookID + "/posts"); //Case Sensitive, Posts doesn´t work
if (result.ToString().Contains("data") && result.data.Count > 0)
{
foreach (var item in result.data)
{
posts.Add(new Post
{
ID = item.id,
Story = item.story,
Message = item.message,
Created_Time = Convert.ToDateTime(item.created_time),
Reactions = GetReactions(item.id)
});
}
result = _facebookClient.Get(GetNextURL(result.ToString()));
}
return posts;
}

Using Facebook Requests 2.0 with the C# SDK

I am trying to update the bookmark count field with the SDK but have not had any success yet.
Can somebody tell me what classes I need to instantiate to do something similar to the following link:
http://developers.facebook.com/blog/post/464
Note:
The link demonstrates how to set the bookmark count and delete it. I would like to be able to do the same with the SDK, any help would be appreciated.
To do this, first you need to get you app's access token:
private string GetAppAccessToken() {
var fbSettings = FacebookWebContext.Current.Settings;
var accessTokenUrl = String.Format("{0}oauth/access_token?client_id={1}&client_secret={2}&grant_type=client_credentials",
"https://graph.facebook.com/", fbSettings.AppId, fbSettings.AppSecret);
// the response is in the form: access_token=foo
var accessTokenKeyValue = HttpHelpers.HttpGetRequest(accessTokenUrl);
return accessTokenKeyValue.Split('=')[1];
}
A couple of things to note about the method above:
I'm using the .Net HttpWebRequest instead of the Facebook C# SDK to grab the app access_token because (as of version 5.011 RC1) the SDK throws a SerializationException. It seems that the SDK is expecting a JSON response from Facebook, but Facebook returns the access token in the form: access_token=some_value (which is not valid JSON).
HttpHelpers.HttpGetRequest simply uses .Net's HttpWebRequest. You can just as well use WebClient, but whatever you choose, you ultimately want to make this http request:
GET https://graph.facebook.com/oauth/access_token?client_id=YOUR_APP_ID&client_secret=YOUR_APP_SECRET&grant_type=client_credentials HTTP/1.1
Host: graph.facebook.com
Now that you have a method to retrieve the app access_token, you can generate an app request as follows (here I use the Facebook C# SDK):
public string GenerateAppRequest(string fbUserId) {
var appAccessToken = GetAppAccessToken();
var client = new FacebookClient(appAccessToken);
dynamic parameters = new ExpandoObject();
parameters.message = "Test: Action is required";
parameters.data = "Custom Data Here";
string id = client.Post(String.Format("{0}/apprequests", fbUserId), parameters);
return id;
}
Similarly, you can retrieve all of a user's app requests as follows:
Note: you probably don't want to return "dynamic", but I used it here for simplicity.
public dynamic GetAppRequests(string fbUserId) {
var appAccessToken = GetAppAccessToken();
var client = new FacebookClient(appAccessToken);
dynamic result = client.Get(String.Format("{0}/apprequests", fbUserId));
return result;
}
I hope this helps.