How to log in to Facebook in Xamarin.Forms

47,912

Solution 1

You could consume either Xamarin.Social or Xamarin.Auth for that. It allows using the same api whatever the platform is.

As of now, those libs aren't PCL yet, but you still can consume them from a Shared Assets Project, or abstract the API you need in an interface and inject in with DependencyService or any other DI container.

Solution 2

UPDATE (10/24/17): While this way of doing things was okay a few years ago, I now strongly advocate for using native UI for doing authentication, as opposed to the webview method shown here. Auth0 is a great way to accomplish native UI login for your apps, using a wide variety of identity providers: https://auth0.com/docs/quickstart/native/xamarin

EDIT: I finally put a sample for this on Gihub

I posted an answer on the Xamarin Forums. I'll repeat it here.

Let's start with the core of the app, the Xamarin.Forms PCL project. Your App class will look something like this:

namespace OAuth2Demo.XForms
{
    public class App
    {
        static NavigationPage _NavPage;
        
        public static Page GetMainPage ()
        {
            var profilePage = new ProfilePage();

            _NavPage = new NavigationPage(profilePage);

            return _NavPage;
        }

        public static bool IsLoggedIn {
            get { return !string.IsNullOrWhiteSpace(_Token); }
        }

        static string _Token;
        public static string Token {
            get { return _Token; }
        }

        public static void SaveToken(string token)
        {
            _Token = token;
        }
        
        public static Action SuccessfulLoginAction
        {
            get {
                return new Action (() => {
                    _NavPage.Navigation.PopModalAsync();
                });
            }
        }
    }
}

The first thing to notice is the GetMainPage() method. This tells the app which screen it should load first upon launching.

We also have a simple property and method for storing the Token that is returned from the auth service, as well as a simple IsLoggedIn property.

There's an Action property as well; something I stuck in here in order to have a way for the platform implementations to perform a Xamarin.Forms navigation action. More on this later.

You'll also notice some red in your IDE because we haven't created the ProfilePage class yet. So, let's do that.

Create a very simple ProfilePage class in the Xamarin.Forms PCL project. We're not even going to do anything fancy with it because that will depend on your particular need. For the sake of simplicity in this sample, it will contain a single label:

namespace OAuth2Demo.XForms
{
    public class ProfilePage : BaseContentPage
    {
        public ProfilePage ()
        {
            Content = new Label () {
                Text = "Profile Page", 
                VerticalOptions = LayoutOptions.CenterAndExpand,
                HorizontalOptions = LayoutOptions.CenterAndExpand, 
            };
        }
    }
}

Again, you'll probably have some red in your IDE because we seem to be missing the BaseContentPage class. The sole purpose of the BaseContentPage class is to ensure that none of the app's screens can be displayed until the user has logged in. (In this simplified demo, we're just persisting the user info to memory, so you'll need to re-login every time the app is run. In a real-world app, you'd be storing the authenticated user info to the device's keychain, which would eliminate the need to login at each app start.)

Create a BaseContentPage class in the Xamarin.Forms PCL project:

namespace OAuth2Demo.XForms
{
    public class BaseContentPage : ContentPage
    {
        protected override void OnAppearing ()
        {
            base.OnAppearing ();

            if (!App.IsLoggedIn) {
                Navigation.PushModalAsync(new LoginPage());
            }
        }
    }
}

There's a few interesting things going on here:

  1. We're overriding the OnAppearing() method, which is similar to the ViewWillAppear method in an iOS UIViewController. You can execute any code here that you'd like to have run immediately before the screen appears.

  2. The only thing we're doing in this method is checking to see if the user is logged in. If they're not, then we perform a modal push to a class called LoginPage. If you're unfamiliar with the concept of a modal, it's simply a view that takes the user out of the normal application flow in order to perform some special task; in our case, to perform a login.

So, let's create the LoginPage class in the Xamarin.Forms PCL project:

namespace OAuth2Demo.XForms
{
    public class LoginPage : ContentPage
    {

    }
}

Wait...why doesn't this class have a body???

Since we're using the Xamatin.Auth component (which does the job of building and presenting a web view that works with the provided OAuth2 info), we actually don't want any kind of implementation in our LoginPage class. I know that seems weird, but bear with me.

The LoginPageRenderer for iOS

Up until this point, we've been working solely in the Xamarin.Forms PCL project. But now we need to provide the platform-specific implementation of our LoginPage in the iOS project. This is where the concept of a Renderer comes in.

In Xamarin.Forms, when you want to provide platform-specific screens and controls (i.e. screens that do not derive their content from the abstract pages in the Xamarin.Forms PCL project), you do so with Renderers.

Create a LoginPageRenderer class in your iOS platform project:

[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]

namespace OAuth2Demo.XForms.iOS
{
    public class LoginPageRenderer : PageRenderer
    {
        public override void ViewDidAppear (bool animated)
        {
            base.ViewDidAppear (animated);

            var auth = new OAuth2Authenticator (
                clientId: "", // your OAuth2 client id
                scope: "", // the scopes for the particular API you're accessing, delimited by "+" symbols
                authorizeUrl: new Uri (""), // the auth URL for the service
                redirectUrl: new Uri ("")); // the redirect URL for the service

            auth.Completed += (sender, eventArgs) => {
            // We presented the UI, so it's up to us to dimiss it on iOS.
            App.SuccessfulLoginAction.Invoke();

            if (eventArgs.IsAuthenticated) {
                // Use eventArgs.Account to do wonderful things
                App.SaveToken(eventArgs.Account.Properties["access_token"]);
            } else {
                // The user cancelled
            }
        };

        PresentViewController (auth.GetUI (), true, null);
            }
        }
    }
}

There are important things to note:

  1. The [assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))] line at the top (and importantly before the namespace declaration) is using the Xamarin.Forms DependencyService. It's not the most beautiful thing in the world because it's not IoC/DI, but whatever...it works. This is the mechanism that "maps" our LoginPageRenderer to the LoginPage.

  2. This is the class in which we're actually using the Xamarin.Auth component. That's where the OAuth2Authenticator reference comes from.

  3. Once the login is successful, we fire off a Xamarin.Forms navigation via App.SuccessfulLoginAction.Invoke();. This gets us back to the ProfilePage.

  4. Since we're on iOS, we're doing all of our logic sinde of the ViewDidAppear() method.

The LoginPageRenderer for Android

Create a LoginPageRenderer class in your Android platform project. (Note that class name you're creating is identical to the one in the iOS project, but here in the Android project the PageRenderer inherits from Android classes instead of iOS classes.)

[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]

namespace OAuth2Demo.XForms.Android
{
    public class LoginPageRenderer : PageRenderer
    {
        protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
        {
            base.OnModelChanged (oldModel, newModel);

            // this is a ViewGroup - so should be able to load an AXML file and FindView<>
            var activity = this.Context as Activity;

            var auth = new OAuth2Authenticator (
                clientId: "", // your OAuth2 client id
                scope: "", // the scopes for the particular API you're accessing, delimited by "+" symbols
                authorizeUrl: new Uri (""), // the auth URL for the service
                redirectUrl: new Uri ("")); // the redirect URL for the service

            auth.Completed += (sender, eventArgs) => {
            if (eventArgs.IsAuthenticated) {
                App.SuccessfulLoginAction.Invoke();
                // Use eventArgs.Account to do wonderful things
                App.SaveToken(eventArgs.Account.Properties["access_token"]);
            } else {
                // The user cancelled
            }
        };

        activity.StartActivity (auth.GetUI(activity));
        }
    }
}

Again, let's take a look at some interesting things:

  1. The [assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))] line at the top (and importantly before the namespace declaration) is using the Xamarin.Forms DependencyService. No difference here from the iOS version of LoginPageRenderer.

  2. Again, this is where we're actually using the Xamarin.Auth component. That's where the OAuth2Authenticator reference comes from.

  3. Just as with the iOS version, once the login is successful, we fire off a Xamarin.Forms navigation via App.SuccessfulLoginAction.Invoke();. This gets us back to the ProfilePage.

  4. Unlike the iOS version, we're doing all of the logic inside of the OnModelChanged() method instead of the ViewDidAppear().

Here it is on iOS:

Xamarin.Auth with Xamarin.Forms iOS example

...and Android:

Xamarin.Auth with Xamarin.Forms Android example

UPDATE: I've also provided a detailed sample at my blog: http://www.joesauve.com/using-xamarin-auth-with-xamarin-forms/

Solution 3

I've created a sample project to show how to create a Facebook login using native Facebook component, not through a webview like the solutions suggested here. You can check it out in this address:

https://github.com/IdoTene/XamarinFormsNativeFacebook

Solution 4

IOS 8: For those who are using @NovaJoe code and are stuck on view, add the code bellow to workaround:

 bool hasShown;

    public override void ViewDidAppear(bool animated)
    {
        if (!hasShown)
        {
            hasShown = true;

            // the rest of @novaJoe code
        }

    }

Solution 5

Here's a good Xamarin.Forms authentication sample. The documentation in the code is nice. It uses a webview to render the login screen, but you can select what login type you want. It also saves a users token so he doesn't have to keep re-logging in.

https://github.com/rlingineni/Xamarin.Forms_Authentication

Share:
47,912

Related videos on Youtube

Morten Lyhr
Author by

Morten Lyhr

Updated on July 09, 2022

Comments

  • Morten Lyhr
    Morten Lyhr almost 2 years

    I want to make a Xamarin.Forms project, targeting iOS, Android and Windows Phone.

    My app needs to authenticate users using Facebook.

    Should I implement login for each platform independently, or use a manual flow? https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.0

    I prefer to have a single implementation of the login flow, and use it on all platforms.

    How can I get a single implementaion of the Facebook login flow?

  • kingdango
    kingdango almost 10 years
    You are an amazing human being. If you are ever in the Grand Rapids, MI area please let me buy you a beer. twitter.com/kingdango
  • NovaJoe
    NovaJoe almost 10 years
    I'd definitely take you up on that tasty beverage! Glad I could help.
  • Renato Todorov
    Renato Todorov almost 10 years
    Awesome answer, it simplifies the use of PageRenderer with a very useful example. Kudos!
  • NovaJoe
    NovaJoe almost 10 years
    I don't always answer questions on SO, but when I do, they're interesting. ;)
  • Mario Galván
    Mario Galván almost 10 years
    I don't know if it is because I am using a shared project but OnModelChanged override method on android is not working neither onmodelChanged PageRenderer does not contain a definition for "OnModel Changed"
  • NovaJoe
    NovaJoe almost 10 years
    @MarioGalván, not sure why that's happening for you. Try running my source. I updated my answer with a Github link. It's at the top of my answer.
  • Mario Galván
    Mario Galván almost 10 years
    @NovaJoe The problem is that I am using another .dll from xamarin you are using v1.0.0.0 and I am using v1.2.1.0 which has a different function called OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e); that obviusly receives different parameters
  • Mario Galván
    Mario Galván almost 10 years
    @NovaJoe Thanks to your answer, I have changed the function and my renderer Is now Working I am using OnElementChanged(ElementChangedEventArgs<Page> e) You sir are awsome!
  • Alexandre
    Alexandre over 9 years
    @NovaJoe For WPhone, do I need to make a custom render too?
  • NovaJoe
    NovaJoe over 9 years
    @Alexandre, correct, you'd need to create a custom renderer for WPhone as well. I don't do a lot of WPhone, so I didn't include one in my example. Correction: according to the Xamarin Component Store, the Xamarin.Auth component is not compatible with WPhone. components.xamarin.com/view/xamarin.auth
  • Alexandre
    Alexandre over 9 years
    Tks @NovaJoe let's wait Xamarin for WPhone version. BTW, I tried to work with your example on IOS 8, didn't work, the view doesn't dismiss, tried a lot of thing without success. Could you help?
  • NovaJoe
    NovaJoe over 9 years
    Nice work! This will help lots of folks. Issue a pull request on my Github repo. Or I might get around to fixing it on my own too.
  • Illuminati
    Illuminati over 9 years
    Guys, has anyone tried this with FB OAuth API? I'm getting hammered with a FB Security Warning.
  • Alexandre
    Alexandre over 9 years
    @Illuminati The security warning is about the redirect URL, make sure you redirect to a VALID URL
  • Illuminati
    Illuminati over 9 years
    @Alexandre , thanks the security error is gotten rid of but my view is still open. I tried your solution and some other suggestion in web to do PopModel/PopRootModel but still no luck. Any idea ?
  • Alexandre
    Alexandre over 9 years
    I had the same problem, a security message was popping on my screen, the solution was to redirect to an valid URL (which no redirects!)
  • Asanka Indrajith
    Asanka Indrajith over 9 years
    As @Mario Galván suggested I changed the OnModelChanged to OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e). but Android app actually exits when it's loads the redirect url.
  • user2236165
    user2236165 over 9 years
    Thank you for your sample project. After i run it on my iOS device and log in I get a page with just a long string. What is this string and how do I use it to get user information back? :)
  • IdoT
    IdoT over 9 years
    This long string is the Facebook authorization token, I'm using this token for sending it to the server, and it calls https://graph.facebook.com/me/?access_token={YOUR_TOKEN} Do you need the user details in the client side?
  • user2236165
    user2236165 over 9 years
    I figured it out. Thanks! On my iOS project it works perfectly, however on my Android project the token is set but the App.PostSuccessFacebookAction in the OnActivityResult-method get a nullReferenceException. Have you ever experienced this issue?
  • IdoT
    IdoT over 9 years
    The mechanism works as follows: you start within you activity (let's call it 'main activity', then the button clicked opens a new activity, which is the 'facebook activity', when the facebook token is fetched, you need to return to your 'main activity'. If you reached the OnActivityResult of the main activity, then you're doing the flow correctly. in which exact line are you getting the null ref?
  • user2236165
    user2236165 over 9 years
    ` protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); if (resultCode == Result.FirstUser) { var token = data.GetStringExtra("facebookToken"); App.PostSuccessFacebookAction(token); }` My code crash on App.PostSuccessFacebookAction(token) However the token do have a value, but it crashes either way.
  • NovaJoe
    NovaJoe about 9 years
    Very cool. It would be nice if Instagram had a native component as well! But for now, we're relegated to either using the webview/auth url or implementing a custom native control.
  • Iducool
    Iducool about 9 years
    Note: Xamarin.Social component supports iOS and Android not window phone
  • Tomás
    Tomás over 8 years
    @IdoT Yes, I have used your code and it works great. About to attempt updating it to use the latest Facebook SDK though - wish me luck! ;-)
  • Wade Tandy
    Wade Tandy over 8 years
    @Alexandre Thanks this was super helpful. Would you mind going into how you found out this info? I was banging my head against the wall for much of the afternoon on iOS 9 with a "attempt to dismiss modal view controller whose view does not currently appear" error before finding your solution. What's the underlying issue here?
  • Loai
    Loai about 8 years
    @MongoBoy thanks for the example, it tells me that the Domain of this url isn't included in the app's domain, how can i solve this problem
  • Manish Jain
    Manish Jain about 8 years
    This is working but it uses MonoTouch.FacebookConnect which needs MonoTouch DLLs. Error CS0012: The type MonoTouch.Foundation.NSObject' is defined in an assembly that is not referenced. Consider adding a reference to assembly monotouch, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065' (CS0012) (project.iOS) forums.xamarin.com/discussion/36918/…
  • Syed Asad Ali
    Syed Asad Ali almost 8 years
    @NovaJoe, can you write a renderer for windows phone? It will be a great help!
  • NovaJoe
    NovaJoe almost 8 years
    @Syed Asad Ali, unfortunately I don't see myself having any time for that in the near future.
  • Encryption
    Encryption almost 8 years
    @NovaJoe what AppDomain did you put into your facebook settings that referred to your development environment? Currently running on an emulator but don't know what Domain URL to set in Facebook settings.
  • Nuri YILMAZ
    Nuri YILMAZ almost 8 years
    @IdoT huge diffrence between web view and native.. do you try any solution for google+ ?
  • SANDEEP
    SANDEEP over 7 years
    I am getting error after do this all."you are not logged in. please login and try again"
  • rafaelbpa
    rafaelbpa about 7 years
    Guys, this code works great on iOS, but on the android renderer I am getting a "Android.Content.ActivityNotFoundException has been thrown:Unable to find explicit activity class {com.example/md550f8a10a740eb4fb6376baab8337ce22.WebAuthenti‌​catorActivity}; have you declared this activity in your AndroidManifest.xml?" when the code reaches activity.StartActivity (auth.GetUI(activity)); Am I missing something??
  • IdoT
    IdoT about 7 years
    @rafaelbpa - Facebook changed their Android SDK and broke my solution, someone upgraded the solution to work with the new SDK - github.com/mikescandy/XamarinFormsNativeFacebook please note I haven't tested it yet.
  • rafaelbpa
    rafaelbpa about 7 years
    SANDEEP on your facebook app, search for Valid OAuth URI Redirect and add facebook.com/connect/login_success.html
  • rafaelbpa
    rafaelbpa about 7 years
    @IdoT but I am not using facebook native, I'm using xamarin auth component. :( It's supposed to work, I mean, I downloaded an example and the code works. But when I try to use on mine... it crashes.. Im so sad right know, 4 days in this shit omg
  • Admin
    Admin over 6 years
    Man anyone to show me how He inserted the FacebookOAuth because me am getting a null exception
  • NovaJoe
    NovaJoe over 6 years
    @IdrisStack, see my new update at the top of the answer. I advocate for people no longer using my answer here. The major drawback is that the auth screen with this method is being shown in a webview, which is less than ideal. Try to do auth with native UI. There are several providers that specialize in this, and I recommend Auth0: auth0.com/docs/quickstart/native/xamarin
  • Admin
    Admin over 6 years
    @NovaJoe , tried to implement the same way to gmail , but am getting an Exception , 2. how can i wire the token to the parameter of OAuth2Authenticator
  • Nico Haase
    Nico Haase about 5 years
    What do you mean by "correct"? Is there only a single way to do this?