I am debugging MVC6 MusicStore. What I've found is that Facebook ExternalIdentity which is accessed in ExternalLoginCallback method does not have an email claim. At the same time my test MVC5 application successfully gets that claim, so it's not the Facebook app problem.
Does anyone know if that is a beta bug?
For some reason this did not work after upgrading to Facebook API v 2.4. However adding .UserInformationEndpoint like this worked:
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,location";
});
You would need to add email in the Facebook authentication options in Startup.cs
app.UseIdentity().UseFacebookAuthentication(options =>
{
options.Scope.Add("email");
});
Related
I am building a test application and testing out externallogins via facebook.
I am using fiddler and when I click the button to login via facebook I am getting code 200 results (but they are locked due to HTTPS), but I am receiving a null value for loginInfo.
Here specifically:
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); // this is null
if (loginInfo == null)
{
return RedirectToAction("Login");
}
I have reset my secret key and that does not work. I have the most updated version of Microsoft.AspNet.Identity.Owin (2.2.1).
What is the deal with this?
Any help is appreciated.
Assuming you created a new Facebook App as well, it'll work on the latest Facebook Api versions. Default templates don't seem to work out of the box anymore, due to Facebook's changing Api. They've reduced the number of fields that are returned by default and all additional fields now have to be specifically asked for.
Have a look at the following post, which contain 2 possible workarounds for this.
Why new fb api 2.4 returns null email on MVC 5 with Identity and oauth 2?
I'm a newbie to app development. I am building a Windows Phone 8.1 app and have followed the tutorial here: http://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-dotnet-backend-windows-store-dotnet-get-started-users-preview/ to add authentication using Facebook. Everything seems to work fine, except that every now and again it appears to stop bringing back any data from my Azure database. Further investigation revealed that the UserId that is being shown from the code below, changes periodically (although I can't quite work out how often it changes).
// Define a member variable for storing the signed-in user.
private MobileServiceUser user;
...
var provider = "Facebook";
...
// Login with the identity provider.
user = await App.MobileService.LoginAsync(provider);
// Create and store the user credentials.
credential = new PasswordCredential(provider,
user.UserId, user.MobileServiceAuthenticationToken);
vault.Add(credential);
...
message = string.Format("You are now logged in - {0}", user.UserId);
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
This code is identical to the code in the tutorial. The Facebook app settings (on the Facebook developers site) confirm that I am using v2.3 of their API so I should be getting app-scoped UserIds back. I have only ever logged in with one Facebook account, so I would expect the UserId to be the same each time, but they're not. The UserId is prefaced with 'sid:', which someone on the Facebook developers group on Facebook itself says stands for Session ID, which they would expect to change, but if that's the case, I can't work out where to get the actual UserId from that I can then store in my database and do useful things with. I'm sure I must be doing something basic wrong, but I have spent hours Googling this and cannot (unusually) find an answer.
Any help would be greatly appreciated.
Thanks!
So dug deeper. This is how Mobile Apps work (I was thinking from a Mobile Services perspective). The issue here is that the Gateway doesn't provide static SIDs, which is what User.userId provides. The work around to this is listed in the migration doc.
You can only get the Facebook AppId on the server.
ServiceUser user = (ServiceUser) this.User;
FacebookCredentials creds = (await user.GetIdentitiesAsync()).OfType< FacebookCredentials >().FirstOrDefault();
string mobileServicesUserId = creds.Provider + ":" + creds.UserId;
You should note, that this Id is directly connected with your Facebook App registration. If you ever want to migrate your App to a new Facebook App, you'd have to migrate them. You can also use the Facebook AppId to look up the user's global facebook Id via the Facebook Graph API, which you could use between applications. If you don't see yourself using multiple apps, etc., you can use the Facebook AppId just fine.
Hard to tell what's going on to cause you to use a SID instead of the Faceboook token (which like Facebook:10153...).
It may be faster to rip out the code and reimplement the Auth GetStarted. Maybe you missed a step or misconfigured something along the way. If you have the code hosted on github, I can try to take a look.
Another thing you can do is to not trust the user to give you their User id when you save it to a table. On your insert function, you can add it there.
function insert(item, user, request) {
item.id = user.userId;
request.execute();
}
That should, theoretically, be a valid Facebook token. Let me know if that doesn't work; can dig deeper.
I have a website (Symfony2) with HWIOauthBundle used to connect with Facebook and everything works fine.
Now, I'm trying to build an iOS app with Cordova and Ionic framework (AngularJS) and I want to authenticate my user with Facebook :
With $cordovaFacebook, I authenticate my user and get a valid Facebook access token, that's ok
I try to use this access token to authenticate my user on the server-side with HWIOauthBundle :
GET http://..../login/facebook?code=MY_FACEBOOK_ACCESS_TOKEN
Symfony rejects my request with this log :
INFO - Matched route "facebook_login" (parameters: "_route": "facebook_login")
INFO - Authentication request failed: OAuth error: "Invalid verification code format."
So my question is : how can I authenticate my user on both front and back end with Facebook connect?
Thanks :)
I've also been wondering how to implement a server side login with the HWIOAuthBundle.
I didn't find any solution on the web, so I coded the functionnality based on hints I've read on the net.
Basically, you have to :
authenticate the user on your app
make an http request to your server with the Facebook token.
ont the server side, check if the token is for your Facebook app, and retrieve the user's Facebook ID.
Get your user from the DB based on the fetched ID.
Here's my Symfony controller:
public function getSecurityFbAction($token)
{
// Get the token's FB app info.
#$tokenAppResp = file_get_contents('https://graph.facebook.com/app/?access_token='.$token);
if (!$tokenAppResp) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Make sure it's the correct app.
$tokenApp = json_decode($tokenAppResp, true);
if (!$tokenApp || !isset($tokenApp['id']) || $tokenApp['id'] != $this->container->getParameter('oauth.facebook.id')) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Get the token's FB user info.
#$tokenUserResp = file_get_contents('https://graph.facebook.com/me/?access_token='.$token);
if (!$tokenUserResp) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Try to fetch user by it's token ID, create it otherwise.
$tokenUser = json_decode($tokenUserResp, true);
if (!$tokenUser || !isset($tokenUser['id'])) {
throw new AccessDeniedHttpException('Bad credentials.');
}
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->findUserBy(array('facebookId' => $tokenUser['id']));
if (!$user) {
// Create user and store its facebookID.
}
// Return the user's JSON web token for future app<->server communications.
}
I throw the Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException exceptions to handle login errors on my app.
Of course, you really should use https because you will be exchanging sensible information.
I don't know if it's the best way to do it but it works well.
Hope it helps !
Well, I think that Symfony doesn't actually reject your request. Facebook is. I'm not sure if this might help, but I know that a bunch a problems can happen when dealing with the Facebook Auth :
Do you know if the tool sends, along with the code parameter, a redirect_uri parameter ? If so :
Did you check that your redirect_uri HAS a trailing slash at the end ? See this
Silly question, but did you check that your app_id is the same when you got authorized via Cordova ?
Check that your redirect_uri DOES NOT have any query parameter.
Check that the redirect_uri that you use during the whole process is the same all the time.
Overall, it seems that your issue is almost all the time related to the redirect_uri URI format.
This post { AppSecret with Windows Phone 7 }
indicates that the WP7 sample doesn't use the AppSecret to login from windows phone, but the current sample in the 5.3.2 download does use the secret.
However, FacebookOAuthClient.cs throws exceptions if it isn't provided. Also, http://blog.prabir.me/post/Facebook-CSharp-SDK-Writing-your-first-Facebook-Application.aspx
shows a sample without using the AppSecret.
Reading Facebooks developer docs it appears that the secret is intended for backend (webserver) auth to facebook, not client apps, and that it is poor practice, maybe insecure, and probably fattening to include your secret in your client application.
Do I misunderstand the guidance, or is there some way to authenticate with the facebook-c#-sdk without using the secret?
Thanks!
In WP 7.0 there was a problem with Fragment in Url (all after # was truncated). Facebook return auth token in Url Fragment, so without it it was impossible to authentificate like desktop/mobile app. The solution was to switch to Web mode, where you can receive auth token if you know AppSecret, so it was the only solution for that (but with security gaps).
In WP 7.1 Fragment Url bug was closed and now you can use normal authentification mode (without AppSecret on client).
If you could access anything of mine WITHOUT first having me authorize the app (solely using the app ID without an access token or a app secret), then that would be a HUGE security hole. Not only to my profile, but to any app out there since the app id is public.
The short answer is, you are required to have a user (or other type of) access token or an app secret to get information.
I figured out the problem was not with the SDK, but the Windows Phone 7 sample included. That sample uses the server-side flow. The changes necessary to the example were:
changing:
loginParameters["response_type"] = "code";
to:
loginParameters["response_type"] = "token";
and removing the entire labda function in webBrowser1_Navigated:
...
// The url is the result of OAuth 2.0 authentication.
if (oauthResult.IsSuccess)
{
var oauthClient = new FacebookOAuthClient { AppId = AppId, AppSecret = AppSecret };
// we got the code here
var code = oauthResult.Code;
oauthClient.ExchangeCodeForAccessTokenCompleted +=
(o, args) =>
{
...
and replaced it with this:
if (_fLoginMode && oauthResult.IsSuccess && !string.IsNullOrEmpty(oauthResult.AccessToken))
{
Dispatcher.BeginInvoke(() => NavigationService.Navigate(new Uri("/FacebookInfoPage.xaml?access_token=" + oauthResult.AccessToken, UriKind.Relative)));
}
And, of course removing the AppSecret constant
Problem is, when a user clicks on FB Login button on my site, Facebook API throws him with a window which ask for access permissions(which is the usual flow). But when the user chooses the proxy mail address (anonymous), then I want to force the user to login only using his real email id.
How am I supposed to handle this ?
I can detect that user used proxy email and prevent him from registering, but then I can't remove my app from his list of authorized apps - meaning I can't get him to that initial dialog for choosing which email he will provide.
You can't force the user to go through the authorization dialog again, because as far as Facebook is concerned, the user has installed your application and nothing else needs to happen. The best thing you can do here is write your own form which informs the user that the Facebook proxy e-mail address is unacceptable and you need a real e-mail address. Unfortunately, this does not force the user to give you their Facebook account e-mail address, or even a real e-mail address. This is the best we have via Facebook though, and it's just something we have to deal with.
UPDATE 5/10/11
I was browsing around the Facebook documentation, and found a method that exists in the old Legacy REST API which actually allows you to remove extended permissions for your app from a user. I think you could use this exact API call to manage getting non-proxy addresses from your Facebook user, while still using the native install dialog.
I tested this using the FB JS SDK and it worked! The method you need to use is the auth.revokeExtendedPermission method. Here are 2 examples of calling that method via the JS SDK and the PHP SDK.
Javascript:
<script>
FB.api({
method: 'auth.revokeExtendedPermission',
perm: 'read_stream'
}, function(response)
{
console.log(response)
});
</script>
PHP:
<?php
$facebook->api(array(
'method' => 'auth.revokeExtendedPermission',
'perm' => 'email',
'uid' => $uid
));
Because these use the Legacy REST API they're not as "supported" as the new Graph API. I've not seen anything regarding migrating this feature to the Graph API. Hopefully they will.
Invoke revocation of the app through graph api (as below) with the php sdk then redirect user back through your dialog with this non-proxy requirement explained.
private function revokeAccess() {
$access_token = $this->facebook->getAccessToken();
$result = $this->facebook->api(array(
'method' => 'auth.revokeAuthorization',
'uid' => $this->{facebook id here},
'access_token' => $access_token
));
return $result;
}
This code is php.
This completely removes the app.
Returns 1 on success; 0 on failure.
$this->facebook == facebook object from the facebook php sdk.