Question

I am trying to authenticate a user on Facebook using the Facebook C# SDK on Windows Phone 8. To do so I am following the code here: FacebookLoginPage.xaml.cs

But the problem I am facing is that, whenever I input my username and password into the dialog that opens to authenticate the user, I just get the following page:

WP8 FB Login Prob

After this, my program does not redirect to the Landing page which is a separate view. The other solutions I have seen that suggest hiding the WebView are not applicable since the authentication is abstracted into a single LoginAsync function call. Any suggestions on what to do?

Was it helpful?

Solution

It would seem that FB has made some changes to its redirection script, when it detects a Windows Phone webbrowser control.

What the C# SDK does, is generate the login page as "http://www.facebook.com....". When you open this URL on the webbrowser control, it gets redirected to "http://m.facebook.com..." which displays the mobile version of the FB login page.

This previously has no issue, but recently, when FB does the redirection, it also strips the parameter "display=page" from the URL. What happens then is that when a successful FB login is made, the "login_success.html" page is opened without this parameter. Without the "display=page" parameter passed in, it defaults to "display=touch". This URL unfortunately, does not append the token string in the URL, hence the page shown in the very first thread is displayed.

The solution to this is, instead of using the below code to generate the login URL, ammend it to

original:

Browser.Navigate(_fb.GetLoginUrl(parameters));

ammended:

var URI = _fb.GetLoginUrl(parameters).toString().replace("www.facebook.com","m.facebook.com");
Browser.Navigate(new Uri(URI));

OTHER TIPS

In my project I just listened for the WebView's navigated event. If it happens, it means that user did something on the login page (i.e. pressed login button). Then I parsed the uri of the page you mentioned which should contain OAuth callback url, if it is correct and the result is success I redirect manually to the correct page:

    //somewhere in the app
    private readonly FacebookClient _fb = new FacebookClient();

    private void webBrowser1_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
    {
        FacebookOAuthResult oauthResult;
        if (!_fb.TryParseOAuthCallbackUrl(e.Uri, out oauthResult))
        {
            return;
        }

        if (oauthResult.IsSuccess)
        {
            var accessToken = oauthResult.AccessToken;
            //you have an access token, you can proceed further 
            FBLoginSucceded(accessToken);
        }
        else
        {
            // errors when logging in
            MessageBox.Show(oauthResult.ErrorDescription);
        }
    }

If you abstract logging in an async function, you expect it to behave asynchronously, so events are ok.

Sorry for my English.

The code for the full page:

public partial class LoginPageFacebook : PhoneApplicationPage
{
    private readonly string AppId = Constants.FacebookAppId;
    private const string ExtendedPermissions = "user_birthday,email,user_photos";
    private readonly FacebookClient _fb = new FacebookClient();
    private Dictionary<string, object> facebookData = new Dictionary<string, object>();
    UserIdentity userIdentity = App.Current.Resources["userIdentity"] as UserIdentity;

    public LoginPageFacebook()
    {
        InitializeComponent();
    }

    private void webBrowser1_Loaded(object sender, RoutedEventArgs e)
    {
        var loginUrl = GetFacebookLoginUrl(AppId, ExtendedPermissions);
        webBrowser1.Navigate(loginUrl);
    }

    private Uri GetFacebookLoginUrl(string appId, string extendedPermissions)
    {
        var parameters = new Dictionary<string, object>();
        parameters["client_id"] = appId;
        parameters["redirect_uri"] = "https://www.facebook.com/connect/login_success.html";
        parameters["response_type"] = "token";
        parameters["display"] = "touch";

        // add the 'scope' only if we have extendedPermissions.
        if (!string.IsNullOrEmpty(extendedPermissions))
        {
            // A comma-delimited list of permissions
            parameters["scope"] = extendedPermissions;
        }

        return _fb.GetLoginUrl(parameters);
    }

    private void webBrowser1_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
    {
        if (waitPanel.Visibility == Visibility.Visible)
        {
            waitPanel.Visibility = Visibility.Collapsed;
            webBrowser1.Visibility = Visibility.Visible;
        }

        FacebookOAuthResult oauthResult;
        if (!_fb.TryParseOAuthCallbackUrl(e.Uri, out oauthResult))
        {
            return;
        }

        if (oauthResult.IsSuccess)
        {
            var accessToken = oauthResult.AccessToken;
            FBLoginSucceded(accessToken);
        }
        else
        {
            // user cancelled
            MessageBox.Show(oauthResult.ErrorDescription);
        }
    }

    private void FBLoginSucceded(string accessToken)
    {

        var fb = new FacebookClient(accessToken);

        fb.GetCompleted += (o, e) =>
        {
            if (e.Error != null)
            {
                Dispatcher.BeginInvoke(() => MessageBox.Show(e.Error.Message));
                return;
            }

            var result = (IDictionary<string, object>)e.GetResultData();
            var id = (string)result["id"];

            userIdentity.FBAccessToken = accessToken;
            userIdentity.FBID = id;

            facebookData["Name"] = result["first_name"];
            facebookData["Surname"] = result["last_name"];
            facebookData["Email"] = result["email"];
            facebookData["Birthday"] = DateTime.Parse((string)result["birthday"]);
            facebookData["Country"] = result["locale"];

            Dispatcher.BeginInvoke(() =>
                {
                    BitmapImage profilePicture = new BitmapImage(new Uri(string.Format("https://graph.facebook.com/{0}/picture?type={1}&access_token={2}", id, "square", accessToken)));
                    facebookData["ProfilePicture"] = profilePicture;

                    userIdentity.FBData = facebookData;
                    userIdentity.ProfilePicture = profilePicture;

                    ARLoginOrRegister();
                });
        };

        fb.GetAsync("me");
    }

    private void ARLoginOrRegister()
    {
        WebService.ARServiceClient client = new WebService.ARServiceClient();
        client.GetUserCompleted += client_GetUserCompleted;
        client.GetUserAsync((string)facebookData["Email"]);
        client.CloseAsync();
    }

    void client_GetUserCompleted(object sender, WebService.GetUserCompletedEventArgs e)
    {
        if (e.Result == null)
            NavigationService.Navigate(new Uri("/RegisterPageFacebook.xaml", UriKind.RelativeOrAbsolute));
        else if (e.Result.AccountType != (int)AccountType.Facebook)
        {
            MessageBox.Show("This account is not registered with facebook!");
            NavigationService.Navigate(new Uri("/LoginPage.xaml", UriKind.RelativeOrAbsolute));
        }
        else
        {
            userIdentity.Authenticated += userIdentity_Authenticated;
            userIdentity.FetchARSocialData((string)facebookData["Email"]);
        }

    }

    void userIdentity_Authenticated(bool success)
    {
        NavigationService.Navigate(new Uri("/MenuPage.xaml", UriKind.RelativeOrAbsolute));
    }
}

Before trying to do all the proposed changes, please check that your Facebook App is not on Sandbox mode. This will eventually resolve your issue.

enter image description here

If your facebook app is in sandbox mode, only the developer can login, using his email address. Any other fb user will get the white page.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top