I have the following code to try connect the authenticator
var auth = new OAuth2Authenticator (
appId,
"email",
new Uri ("https://m.facebook.com/dialog/oauth/"),
new Uri ("http://www.facebook.com/connect/login_success.html"));
and when the dialog shows, I can see that it is requesting permission to see my email. But how do I get that email from the service?
I make the following call to get the Facebook ID
var request = new OAuth2Request ("GET", new Uri ("https://graph.facebook.com/me"), null, args.Account);
request.GetResponseAsync ().ContinueWith (t => {
var obj = JsonValue.Parse (t.Result.GetResponseText ());
var id = obj ["id"];
});
But there is no email in the reponse that I get back. How can I get the email address of the user?
The lastest API version (2.4 at time of writing) uses Declarative Fields, so you need to explicitly request the email field like this:
https://graph.facebook.com/me?fields=email
Related
I use Google ID tokens to sign in users to my webservice. As part of validating the token it receives from Google, the webservice checks that email_verified = true in the token's payload.
Some of my users signed up for a Google-account with their non-Gmail, non-Google Apps email address. They did click the link in the email that Google sent them after sign-up, to verify their email address.
When those users try to login to my webservice, I get email_verified = false in the token's payload.
What does this mean and can/ should I ignore this in validating the token?
There are a couple of different ways in which you can validate the integrity of the ID token on the server side:
"Manually" - constantly download Google's public keys, verify signature and then each and every field, including the iss one; the main advantage (albeit a small one in my opinion) I see here is that you can minimize the number of requests sent to Google.
"Automatically" - do a GET on Google's endpoint to verify this token
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}
Using a Google API Client Library - like the official one.
Here's how this could look:
private const string GoogleApiTokenInfoUrl = "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}";
public ProviderUserDetails GetUserDetails(string providerToken)
{
var httpClient = new MonitoredHttpClient();
var requestUri = new Uri(string.Format(GoogleApiTokenInfoUrl, providerToken));
HttpResponseMessage httpResponseMessage;
try
{
httpResponseMessage = httpClient.GetAsync(requestUri).Result;
}
catch (Exception ex)
{
return null;
}
if (httpResponseMessage.StatusCode != HttpStatusCode.OK)
{
return null;
}
var response = httpResponseMessage.Content.ReadAsStringAsync().Result;
var googleApiTokenInfo = JsonConvert.DeserializeObject<GoogleApiTokenInfo>(response);
if (!SupportedClientsIds.Contains(googleApiTokenInfo.aud))
{
Log.WarnFormat("Google API Token Info aud field ({0}) not containing the required client id", googleApiTokenInfo.aud);
return null;
}
return new ProviderUserDetails
{
Email = googleApiTokenInfo.email,
FirstName = googleApiTokenInfo.given_name,
LastName = googleApiTokenInfo.family_name,
Locale = googleApiTokenInfo.locale,
Name = googleApiTokenInfo.name,
ProviderUserId = googleApiTokenInfo.sub
};
}
I've built a client (in .NET, but it could be in any framework) to consume the Payflow Gateway NVP API using the Transparent Redirect and Secure Token features. I am able to receive the token, send the credit card data, and receive an Approved response from PayPal. The problem is that PayPal is not redirecting properly back to my site. I passed a RETURNURL (http://localhost:49881/transaction/details?processor=PayflowGateway) parameter when requesting the Secure Token, but instead of returning me to that URL after the transaction, it navigates my browser to the following URL:
https://pilot-payflowlink.paypal.com/http%3A%2F%2Flocalhost%3A49881%2Ftransaction%2Fdetails%3Fprocessor%3DPayflowGateway?POSTFPSMSG=No%20Rules%20Triggered&RESPMSG=Approved&ACCT=1111&COUNTRY=US&PROCCVV2=M&VISACARDLEVEL=12&CVV2MATCH=Y&CARDTYPE=0&PNREF=A70A8EB8B6A1&AVSDATA=XXN&SECURETOKEN=9eGKZsSldEU6mIdSEV5DB4wWd&PREFPSMSG=No%20Rules%20Triggered&SHIPTOCOUNTRY=US&AMT=14.75&SECURETOKENID=1850a8f2-f180-4474-aa31-35d736fd7921&TRANSTIME=2016-03-24%2007:58:48&HOSTCODE=A&COUNTRYTOSHIP=US&RESULT=0&BILLTOCOUNTRY=US&AUTHCODE=872PNI&EXPDATE=1218
I have tried removing the "?processor=PayflowGateway" to fix the multiple question mark issue in the URL, but that doesn't seem to help. I've also tried tagging the RETURNURL[xx] with xx being the length of the URL value, but that seems to be the same as not passing a RETURNURL at all as it just shows a confirmation page on paypal.com instead of redirecting back to my site.
In PayPal Manager, I set the "Show confirmation page" setting to "On my website", Return URL to blank, and Return URL Method to GET. Are there any other settings or API request changes I need to make to get this to return properly to my test site?
This problem is caused because you're URL-Encoding the RETURNURL parameter passed when requesting the secure token from payflowpro gateway.
See the Do Not URL Encode Name-Value Parameter Data section on the Integration Guide.
Also, here you can get some C# code working you can use.
And some guidelines about PayPal HTTP here.
Do not use System.Net.Http.HttpClient nor System.Net.WebClient to make the HTTP POST to request the secure token. Instead use the low level System.Net.WebRequest to be able to write the POST data unencoded.
For example:
private string RequestSecureToken(double amount)
{
var secureTokenId = Guid.NewGuid().ToString();
var requestId = Guid.NewGuid().ToString();
var pairs = new Dictionary<string, string>()
{
{"PARTNER", "PayPal"},
{"VENDOR", "VENDOR NAME"},
{"USER", "USER NAME"},
{"PWD", "PASSWORD"},
{"TRXTYPE", "S"},
{"AMT", amount.ToString()},
{"CREATESECURETOKEN", "Y"},
{"SECURETOKENID", secureTokenId},
{"SILENTTRAN", "TRUE"},
{"RETURNURL", "http://mycompany.com/success"},
{"ERRORURL", "http://mycompany.com/error"}
};
string postData = string.Join("&", pairs.Select(p => string.Format("{0}[{2}]={1}", p.Key, p.Value, p.Value.Length)));
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://pilot-payflowpro.paypal.com");
request.Method = "POST";
request.ContentType = "text/namevalue";
request.Headers.Add("X-VPS-CLIENT-TIMEOUT", "45");
request.Headers.Add("X-VPS-REQUEST-ID", requestId);
request.ContentLength = postData.Length;
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(postData);
}
//Get the response
var response = request.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream()))
{
return reader.ReadToEnd();
}
}
I have a Grails project (v2.4.2) that is making use of the spring-security-facebook:0.17 plugin to authenticate via Spring Security. At first sight, all seems well. However, there is a large set of users that for some unknown reason I cannot access their email address. I am using spring social to grab the email. I have permission and it is set in the scope. Here is a code snippet where I authenticate a new user:
log.info("Create domain for facebook user $token.uid")
//Use Spring Social Facebook to load details for current user from Facebook API
log.info("create: FacebookAuthToken: $token")
log.info("created FacebookAuthToken.FacebookAccessToken = ${token.accessToken}")
Facebook facebook = new FacebookTemplate(token.accessToken.accessToken)
org.springframework.social.facebook.api.User fbProfile = facebook.userOperations().getUserProfile()
// Check if email is actual granted because in production some are coming back null
boolean isEmailGranted=false
List<Permission> permissions = facebook?.userOperations()?.getUserPermissions()
String permissionString = "["
for (int i=0;i<permissions.size();i++) {
permissionString += "["+ permissions[i].getName() + ":" + permissions[i].getStatus()+"]"
if (permissions[i].getName()=="email" && permissions[i].isGranted())
isEmailGranted=true
}
permissionString += "]"
log.info("create: Facebook Permissions = " + permissionString)
def grailsWebRequest = WebUtils.retrieveGrailsWebRequest()
def flash = grailsWebRequest.flashScope
if (!isEmailGranted) {
log.warn("create: Unable to subscribe facebook user because email priviledge was not granted.")
flash.message = 'Login to Facebook failed. We must have access to your email address in order to proceed with login.'
throw new InsufficientAuthenticationException("Facebook email not accessible")
}
log.info("created: ")
String email = fbProfile.getEmail()
String firstName = fbProfile.getFirstName()
String lastName = fbProfile.getLastName()
String fullName = fbProfile.getName()
String username = firstName
String password = token.accessToken.accessToken
if (!email) {
log.error("create: Permission was granted to use facebook email but the value is null.")
flash.message = 'Login to Facebook failed. We are temporarily unable to access your email although permission has been granted'
throw new InsufficientAuthenticationException("Facebook email not accessible for unknown reason")
}
Why would I receive an empty email when permission has been granted? Is there a preferred method for handling this behavior (other than failing the authentication and making up a fake email address). Many thanks!
The documentation for the 'email' field of the 'user' object ( https://developers.facebook.com/docs/reference/api/user/ ) clarifies the expected behaviour here, which is:
"this field will not be returned if no valid email address is available"
There is a detailed explanation about different situations where an email won't be sent. Please check it out:
https://developers.facebook.com/bugs/298946933534016/
I hope it helps.
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.
I am using https://github.com/sanjeevdwivedi/facebook-csharp-sdk to integrate facebook in my wp8 app.
I want to know how to access the user email id using facebook-csharp-sdk below is the code I am using
FacebookSession session = FacebookSessionClient.LoginAsync("user_about_me,read_stream");
FacebookClient _fb = new FacebookClient(session.AccessToken);
dynamic parameters = new ExpandoObject();
parameters.access_token = session.AccessToken;
parameters.fields = "email,first_name,last_name";
dynamic result = await _fb.GetTaskAsync("me", parameters);
But I am getting only firstname , lastname and id of the logged in result field. Please suggest where am i missing?
You should ask for the email permission.
FacebookSession session = FacebookSessionClient.LoginAsync("user_about_me,read_stream,email");
The last item in the LoginAsync params I placed is email
See permissions for more info