How can I get full facebook profile from ASP.NET MVC - c#

I am developing web app, where I need to get full information about facebook user. OAUTH2 login is done successfully. But after that when I call graph.facebook.api using provided access token I get only id, name and picture.
The question is how can I get full user profile from facebook?
In Startup.Auth.cs I have following code:
var facebookAuthOptions = new FacebookAuthenticationOptions()
{
AppId = "APP_ID_HERE",
AppSecret = "APP_SECRET_HERE",
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:accesstoken"
, context.AccessToken
, ClaimValueTypes.String
, "Facebook"));
context.Identity.AddClaim(new Claim("urn:facebook:email"
, context.AccessToken
, ClaimValueTypes.Email
, "Facebook"));
context.Identity.AddClaim(new Claim("urn:facebook:about"
, context.AccessToken
, ClaimValueTypes.String
, "Facebook"));
return Task.FromResult(0);
}
}
};
app.UseFacebookAuthentication(facebookAuthOptions);
And in my controller I am calling facebook API like this:
var apiRequestUri = new Uri("https://graph.facebook.com/v2.8/me?fields=email,name,about,picture&access_token=" + accessToken);
var webClient = new System.Net.WebClient();
var json = webClient.DownloadString(apiRequestUri);
var profile = JsonConvert.DeserializeObject<FacebookProfile>(json);
But what I get is only id, name and picture.
When I try similar query in graph api console, I can get all of the information required.
Any suggestions are welcome!
Thank you in advance for your help!

I have resolved this by adding claims to the facebookAuthOptions for each of the field required. After user approves requested info, then I can successfully get response from Facebook API using token provided on authorization step.

Related

Create users in ASP.NET Core web app using Active Directory authentication

How can I Create/Edit users in an ASP.NET Core web app that use OAuth or OpenID Connect to authentication?
All the documentation and examples I have found allow the users to sign-up.
e.g.(active-directory-dotnet-webapp-openidconnect-aspnetcore)
The requirements I have are the ability to create/edit users and assign roles in our database AND then allow those users to login to the web app using Azure AD.
If you are building an app which may include azure ad user management , and want to create/edit users after admin user login . You could firstly refer to below code sample about how to call a web API in an ASP.NET Core web application using Azure AD :
https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore
Then you could use Azure AD graph api to create azure ad users :
Firstly register the app in azure portal , setting redirect url(https://localhost:44371/signin-oidc for example) , add a key ,configure permissions for your application , To use azure ad graph api , you need to choose Windows Azure Active Directory ,and set delegate permission Read and write directory data(require admin consent) .
In the controller action(HttpPost) , you could use below code to create a user :
AuthenticationResult result = null;
try
{
string userObjectID = (User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID, HttpContext.Session));
ClientCredential credential = new ClientCredential(Startup.ClientId, Startup.ClientSecret);
result = await authContext.AcquireTokenSilentAsync("https://graph.windows.net", credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
var userData = new
{
accountEnabled = true,
displayName = "nan yu",
mailNickname = "nanyu",
passwordProfile = new
{
password = "xxxxxx",
forceChangePasswordNextLogin = false
},
userPrincipalName = "nanyuTest54#testbasic1.onmicrosoft.com"
};
// Forms encode todo item, to POST to the Azure AD graph api.
HttpContent content = new StringContent(JsonConvert.SerializeObject(userData), System.Text.Encoding.UTF8, "application/json");
//
// Add the azure ad user.
//
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://graph.windows.net/myorganization/users?api-version=1.6");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
request.Content = content;
HttpResponseMessage response = await client.SendAsync(request);
//
// Return user in the view.
//
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
//
// If the call failed with access denied, then drop the current access token from the cache,
// and show the user an error indicating they might need to sign-in again.
//
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
}
}
}
catch (Exception ee)
{
//
// The user needs to re-authorize. Show them a message to that effect.
//
}
If i misunderstand your requirement , please feel free to let me know .

How do you retrieve a users' access token and secret in ASP.NET 5 Identity?

I'm developing a small app that allows a user to login to the site with their Twitter account. Then, once that is done, I intend to use the account to perform various actions with the Twitter API. However in order to do this I require the previously obtained access token and secret, but I don't know how.
I'm using .NET Core ASP.NET v5 on the boilerplate WebApp. Twitter authentication setup with:
app.UseTwitterAuthentication(new TwitterOptions()
{
ConsumerKey = "BLAH",
ConsumerSecret = "BLAH"
});
How do I retrieve the stored access token and secret once a user has successfully logged in with the Twitter auth?
I assume it is something along the lines of User.Identity.* or User.Claims.*.
You just need to add the values to the user's claims on authentication. In your Startup.Auth.cs, you'll need to add the following:
var twitterOptions = new Microsoft.Owin.Security.Twitter.TwitterAuthenticationOptions
{
ConsumerKey = /* Your App's Consumer Key */,
ConsumerSecret = /* Your App's Consumer Secret */,
Provider = new Microsoft.Owin.Security.Twitter.TwitterAuthenticationProvider
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:twitter:access_token", context.AccessToken, XmlSchemaString, "Twitter"));
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:twitter:access_token_secret", context.AccessTokenSecret, XmlSchemaString, "Twitter"));
return Task.FromResult(0);
}
}
};
app.UseTwitterAuthentication(twitterOptions);
Then, when you need the values, you can retrieve them via:
var twitterTokenClaim = user.Claims.FirstOrDefault(m => m.ClaimType.EndsWith("twitter:access_token"));
var twitterSecretClaim = user.Claims.FirstOrDefault(m => m.ClaimType.EndsWith("twitter:access_token_secret"));
These are actual IdentityClaim instances, though, so you'll need to properly null-check and then access their ClaimValue property:
if (twitterTokenClaim != null && twitterSecretClaim != null)
{
// work with Twitter API
// Token and secret string values accessed via `twitterTokenClaim.ClaimValue`
// and `twitterSecretClaim.ClaimValue`, respectively
}

Microsoft Bot Framework - Facebook authentication, account linking

I want to authorize user through bot and get proper information from database while chatting.
User is registered to my website database using facebook account.
So far, I have this:
var resultMessage = context.MakeMessage();
resultMessage.Type = "message";
resultMessage.Attachments = new List<Attachment>();
List<CardAction> cardButtons = new List<CardAction>();
List<CardAction> plButton = new List<CardAction>();
plButton.Add(new CardAction
{
Value = "myurl/link",
Type = "signin",
Title = "LogIn"
});
SigninCard plCard = new SigninCard("You need to authorize me", plButton);
Attachment plAttachment = plCard.ToAttachment();
resultMessage.Attachments.Add(plAttachment);
On the other side, where I should authorize the user, I have this:
public Uri link(string resource, string clientId, Uri redirectUri, User userId, string extraQueryParameters)
{
return redirectUri;
}
But that's not correct.
What parameters should I send?
How to handle this?
How to redirect user on Facebook Messenger, again?
How to authenticate and get (stored) userdata from my database into bot ?
Thank you in advance for your replies!

Register External Login Web API

I don't understand why their isn't a clear tutorial or guideline on this, so I hope my question can be answered here.
So, trying to register users from facebook or google, via the Web Api.
The problem is, at the RegisterExternal method, on this line:
var info = await Authentication.GetExternalLoginInfoAsync();
It returns null, and thus returning a BadRequest()
What I got so far:
In Startup.Auth.cs I've hadded the id's and the secrets, note that I have also tried using Microsoft.Owin.Security.Facebook
var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions
{
AppId = "103596246642104",
AppSecret = "1c9c8f696e47bbc661702821c5a8ae75",
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, ClaimValueTypes.String, "Facebook"));
return Task.FromResult(0);
}
},
};
facebookOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookOptions);
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId = "328779658984-t9d67rh2nr681bahfusan0m5vuqeck13.apps.googleusercontent.com",
ClientSecret = "ZYcNHxBqH56Y0J2-tYowp9q0",
CallbackPath = new PathString("/api/Account/ManageInfo")
});
facebookOptions source: this post
That extra facebookOptions did not solve the problem.
I am able to retrieve an access_token from both Google and Facebook. I'm also able to Authenticate with this access_token to api/Account/UserInfo
GET http://localhost:4856/api/Account/UserInfo
in the header:
Authorization: Bearer R9BTVhI0...
Which returns:
{"Email":"firstname lastname","HasRegistered":false,"LoginProvider":"Facebook"}
One issue I notice their, is that it returns my name as Email, not the actual Email adress.
Now I want to register the external login with a new user for my database, which I make a POST call like this:
POST http://localhost:4856/api/Account/RegisterExternal
[header]
authorization: bearer 6xcJoutY...
Content-Type: application/json
[body]
{"Email":"...#hotmail.com"}
source: this post
Now this returns a BadRequest on this code snippit, inside RegisterExternal():
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//AuthenticationManger?
var info = await Authentication.GetExternalLoginInfoAsync();
if (info == null)
{
return InternalServerError();
}
In debugging, the ExternalLoginConfirmationViewModel does contain my email adress.
What am I doing wrong? Do I have to add something to the Startup.cs? Is there something more I have to do in the Startup.Auth.cs? Am I incorrectly calling RegisterExternal? In MVC it goes so smooth, why not in the Web API?
Aso looked at this answer from this question, But I didn't understand how to implement this.
This method is not really practical, since you are developing an API, that will most likely be used for apps, you best way is to handle the login with facebook by the API consumer, and let them send you an facebook auth token.
Basically I was trying to do this:
Create external login link for facebook.
Send user to that link that will bring them to facebook login page.
After login facebook will redirect to api.
User would be registered, but how does the app/website that is consuming the API know?
What you want to do is this:
API consumer creates their own method to login with facebook (for apps via SDK's)
API consumer will send an facebook token to the API to register/login.
API will check token with facebook graph endpoint.
When succeeded, API will return an bearer token for the API to make further authenticated requests.
So for you as an API developer, you would verify the token like so:
var verifyTokenEndPoint = string.Format("https://graph.facebook.com/debug_token?input_token={0}&access_token={1}", accessToken, appToken);
And then get the userId
var client = new HttpClient();
var uri = new Uri(verifyTokenEndPoint);
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
dynamic jObj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(content);
string user_id = jObj["data"]["user_id"];
string app_id = jObj["data"]["app_id"];
}
Eventually you would create or find a user like so:
IdentityUser user = await _userManager.FindAsync(new UserLoginInfo(provider, verifiedAccessToken.user_id));
And then it's all up to you how to create an bearer token, if you follow the tutorial listed below, you could have this:
var tokenExpiration = TimeSpan.FromMinutes(30);
ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, userName));
identity.AddClaim(new Claim("role", "user"));
var props = new AuthenticationProperties()
{
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.Add(tokenExpiration),
};
var ticket = new AuthenticationTicket(identity, props);
var accessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
Source, with full tutorial here
I've also got the email via the SDK and send that along with the POST request, since I managed both the API and the consumer. Warning though: A facebook user might not want to give you an e-mail address.
Get e-mail after facebook login on Android and IOS

Request additional claims Owin Security

I am trying to retrieve additional information from a google OAuth handshake using OWIN Security.
I have the following to request the user profile claim from Google and the google permissions page reflects that this claim is requested.
var googleConfig = new Microsoft.Owin.Security.Google.GoogleOAuth2AuthenticationOptions
{
ClientId = ClientId",
ClientSecret = "Secret"
};
googleConfig.Scope.Add("https://www.googleapis.com/auth/userinfo.profile");
app.UseGoogleAuthentication(googleConfig);
However when i get the response back using AuthenticationManager.GetExternalLoginInfoAsync(); there is only one name claim on the user.
What do i need to do to get back the user profile data from google on login?
You need to access the additional claims in the Provider's OnAuthenticate event. In there the context param contains these additional properties you asked for in the scopes. For exmaple, when using Facebook:
var fb = new FacebookAuthenticationOptions
{
AppId = "...",
AppSecret = "...",
AuthenticationType = "Facebook",
SignInAsAuthenticationType = "ExternalCookie",
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = async ctx =>
{
if (ctx.User["birthday"] != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.DateOfBirth, ctx.User["birthday"].ToString()));
}
}
}
};
fb.Scope.Add("user_birthday");
app.UseFacebookAuthentication(fb);

Categories