共用方式為


Using the Facebook Android SDK for logging in to Azure Mobile Services

When an application needs to login to an Azure Mobile Service to access protected resources, there are basically two ways to do that. One is using what I called the server-side (or web-based) authentication flow, which I mentioned in a few previous posts – the SDK will show a web control with the login page from the authentication provider, and after the user enters their credentials, the application receives an authentication token which can be sent in subsequent requests to the server, at which points considers the client to be logged in. The other way (which currently works for Facebook, Google and Microsoft accounts) is to use a native SDK from the authentication provider, and then take some information from the SDK itself and use that to log in to the Azure Mobile Service. This way is what I call a client-side authentication flow: all the authentication logic is done at the client side (from the perspective of the mobile service), with a later step to exchange that information for a Mobile Service authentication token.

Using one authentication flow or the other is mostly due to personal preference and the maturity of the application. Using the native SDKs for authentication (client flow) will more likely give a better integrated experience with the device, so more polished apps tend to use that option. Using the server flow (web-based authentication) is simpler to implement (no need to use an external component), and for many cases the UI is good enough that there is no need for the extra effort required to show the more integrated authentication dialog. Usually in the apps I built I start with the server-side flow and in a couple of them I decided to make them a little prettier and moved to the client-side flow.

The documentation for authentication with the client-side flow is not as extensive as the one for the server side. Authenticating with the Live SDK for Windows Store and Windows Phone applications is well documented in windowsazure.com, so I decided to write a few posts about using other authentication providers for other platforms. This is about using the Facebook Android SDK for authenticating with an Azure Mobile Service, and future posts will cover other SDKs as well.

Getting the Facebook Android SDK

The first thing you need is the Facebook Android SDK, which can be downloaded at the Facebook site. The “Getting Started” page in the Facebook docs for their Android SDK is fairly good, and it comes in two flavors, depending on your editor: Eclipse or Android Studio. I use mostly Eclipse, so that’s what I’ll use for this post, but you should be able to follow the getting started tutorial and come back once we get to the integration with the mobile service client.

After downloading (and unzipping) the SDK, you’ll need to import the Facebook SDK to Eclipse (File –> Import –> Android –> “Existing Android Code Into Workspace”, or File –> Import –> General –> “Existing Projects Into Workspace”; both options worked for me). Browse to the location where you unzipped the FB SDK, and select the “FacebookSDK” project (you can ignore the samples). In the FB tutorial it says that you shouldn’t check the “Copy projects into workspace” option, but you can check that if you want your projects contained in the same location (if you check that box, you will need to update the reference to the samples if you also imported them).

Creating a Facebook App

I’m assuming at this point that you already have a mobile service created, so I’ll skip that part. The page at https://www.windowsazure.com/en-us/develop/mobile/how-to-guides/register-for-facebook-authentication/ shows how to create the Facebook app, and enable the web-based login option (“Website with Facebook Login”). Instead, select the “Native Android App” option, where we’ll fill the information about the Android app.

The package name and the activity name (fully-qualified, with the namespace) can be found at the main activity in the project. The key hash is used by Facebook to uniquely identify, in conjunction with the package name, the app which is being authenticated. Also make sure to enable the “Facebook Login” option in the Facebook app.

001-FacebookApp-AndroidSettings

The getting started guide from Facebook shows the following command to generate the key hash (for windows, with the development store, line feeds added for clarity; the Mac version and the parameters for the release key store are shown in the getting started page):

 keytool -exportcert -alias androiddebugkey
    -keystore %HOMEPATH%\.android\debug.keystore |
    openssl sha1 -binary | openssl base64

I didn’t have neither the keytool.exe nor the openssl.exe in my path, but I was able to find the former in my Java Development Kit (‘C:\Program Files\Java\jdk1.7.0_25\bin’ in my computer) and the latter in my Git installation (‘C:\Program Files (x86)\Git\bin’ in my computer), so you may have those in your computer already even if not in the path. Running that command will give you the hash of the key which you’ll need to add to the app on the Facebook developers site.

The remaining thing to do is to copy the App ID and App Secret from the Facebook App page to the identity tab in your mobile service, to associate one with the other.

Hooking up the Facebook SDK to the Android APP

This part is the one that I thought the experience could be better (I’m using to NuGet or node.js / npm packages which configure their dependencies fairly easy). There are a lot of steps, and although they’re all very well described in the getting started guide, if you miss one (and you’re not a seasoned Android developer), it will not work. I’ll summarize the steps here:

  • Right-click your project in Eclipse, select Properties, select Android on the left, and Add in the library section. Select the FacebookSDK project which you imported earlier to Eclipse
  • Under res/values/strings.xml, add a new string, with name “app_id”, and value equal to the App ID shown in the Facebook developer site in the page for your application
  • On AndroidManifest.xml, add a new uses-permission named “android.permission.INTERNET” (under the root node)
  • On AndroidManifest.xml, add a new meta-data item called “com.facebook.sdk.ApplicationId” with the value “@string/app_id” (under the application node)
  • On AndroidManifest.xml, add a new activity with name “com.facebook.LoginActivity” (under the application node)
  • On the main activity class, override the onActivityResult method to let the Facebook SDK handle the result of the authentication dialog, by delegating the code to the SDK’s com.facebook.Session class:
      1. @Override
      2. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      3.     super.onActivityResult(requestCode, resultCode, data);
      4.     Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
      5. }
  • Add the code to initiate the Facebook login. In this case I’m adding the code to the onCreate method so that the login will happen when the application starts (this assumes that the layout contains a text view with id ‘textView1’):
      1. Session.openActiveSession(this, true, new StatusCallback() {
      2.  
      3.     @Override
      4.     public void call(Session session, SessionState state, Exception exception) {
      5.         if (session.isOpened()) {
      6.             TextView tv = (TextView)findViewById(R.id.textView1);
      7.             tv.setText("Logged in to Facebook!");
      8.         }
      9.     }
      10. });

And with that you should have the Facebook login set in the application. If the Facebook app is installed in the device, it will be used to prompt for the login credentials (if the user is not already logged in to the device). Otherwise the Facebook SDK will present a webview-like control to prompt for the credentials.

Logging in to the mobile service

With the user logged in to Facebook, we can now log in to the mobile service, to be able to access tables and APIs which require authenticated users. What we need is to retrieve an access token from the session object. The format for the object required for the client-side login flow for Facebook is {“access_token”:”<the actual access token">}, and we can create it using a JsonObject, as shown below. Notice that you’ll need to have the jar files from the Azure Mobile Service SDK for Android in the /libs folder of your Eclipse project. Once we have the JSON object set, we can pass it to the login method, and the implementation of the UserAuthenticationCallback interface is the same as the one which you’d have used for the server-side flow.

  1. Session.openActiveSession(this, true, new StatusCallback() {
  2.     @Override
  3.     public void call(Session session, SessionState state, Exception exception) {
  4.         if (session.isOpened()) {
  5.             String accessToken = session.getAccessToken();
  6.             JsonObject body = new JsonObject();
  7.             body.addProperty("access_token", accessToken);
  8.             mClient.login(MobileServiceAuthenticationProvider.Facebook, body, new UserAuthenticationCallback() {
  9.                 @Override
  10.                 public void onCompleted(MobileServiceUser user,
  11.                         Exception error, ServiceFilterResponse response) {
  12.                     TextView tv = (TextView)findViewById(R.id.textView1);
  13.                     if (error != null) {
  14.                         String err = "Error: " + error.toString();
  15.                         Throwable t = error.getCause();
  16.                         while (t != null) {
  17.                             err = err + "\n  Cause: " + t.toString();
  18.                             t = t.getCause();
  19.                         }
  20.                         
  21.                         tv.setText(err);
  22.                     } else {
  23.                         tv.setText("Logged in to the mobile service as " + user.getUserId());
  24.                     }
  25.                 }
  26.             });
  27.         }
  28.     }
  29. });

Putting it all together, this is what the code of the MainActivity in my project looks like:

  1. public class MainActivity extends Activity {
  2.  
  3.     private MobileServiceClient mClient;
  4.     
  5.     @Override
  6.     protected void onCreate(Bundle savedInstanceState) {
  7.         super.onCreate(savedInstanceState);
  8.         setContentView(R.layout.activity_main);
  9.         
  10.         try {
  11.             mClient = new MobileServiceClient(
  12.               "https://mobileservicename.azure-mobile.net/",
  13.               "APPLICATION_KEY",
  14.               this);
  15.         } catch (MalformedURLException e) {
  16.             e.printStackTrace();
  17.         }
  18.  
  19.         Session.openActiveSession(this, true, new StatusCallback() {
  20.  
  21.             @Override
  22.             public void call(Session session, SessionState state, Exception exception) {
  23.                 if (session.isOpened()) {
  24.                     String accessToken = session.getAccessToken();
  25.                     JsonObject body = new JsonObject();
  26.                     body.addProperty("access_token", accessToken);
  27.                     mClient.login(MobileServiceAuthenticationProvider.Facebook, body, new UserAuthenticationCallback() {
  28.                         @Override
  29.                         public void onCompleted(MobileServiceUser user,
  30.                                 Exception error, ServiceFilterResponse response) {
  31.                             TextView tv = (TextView)findViewById(R.id.textView1);
  32.                             if (error != null) {
  33.                                 String err = "Error: " + error.toString();
  34.                                 Throwable t = error.getCause();
  35.                                 while (t != null) {
  36.                                     err = err + "\n  Cause: " + t.toString();
  37.                                     t = t.getCause();
  38.                                 }
  39.                                 
  40.                                 tv.setText(err);
  41.                             } else {
  42.                                 tv.setText("Logged in to Zumo as " + user.getUserId());
  43.                             }
  44.                         }
  45.                     });
  46.                 }
  47.             }
  48.         });
  49.     }
  50.     
  51.     @Override
  52.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  53.         super.onActivityResult(requestCode, resultCode, data);
  54.         Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
  55.     }
  56.  
  57.     @Override
  58.     public boolean onCreateOptionsMenu(Menu menu) {
  59.         // Inflate the menu; this adds items to the action bar if it is present.
  60.         getMenuInflater().inflate(R.menu.main, menu);
  61.         return true;
  62.     }
  63.  
  64. }

That should be it. I personally found that the Facebook SDK for Android is quite easy to use, with nice methods to talk to the FB Graph API. The documentation on FB also lists some potential pitfalls and some troubleshooting guide.

Comments

  • Anonymous
    August 20, 2014
    Interessting post. Can I do the same thing using the .NET backend?

  • Anonymous
    August 21, 2014
    Not currently - logging in to a .NET backend mobile service with a token acquired from the auth provider is not supported yet.

  • Anonymous
    August 26, 2014
    Not currently?! :) Will it be supported? Are you working with it?

  • Anonymous
    August 27, 2014
    Yes, this is in the backlog of items that we need to implement to get the .NET backend in feature-parity with the node.js one.

  • Anonymous
    August 12, 2015
    Hi there, I want to use Facebook SDK to log in azure mobile service and google lead me here. Unfortunately Facebook updated their SDK to 4.x and the Session function has removed. Howerver some new classes support old functions, but it came out the azure mobile service login API cannot work now. I used mobileServiceClient.login(MobileServiceAuthenticationProvider.Facebook, jsonObject) to login (since the one with UserAuthenticationCallback has deprecated), but it seems the token I turned in has some problem. (AccessToken.getCurrentAccessToken().getToken(), the class AccessToken is a parcelable object and there's a String object name "token" so I get it for parameter, I've printed it and it did look like a token string) Anyway, the callback of login just don't response. If you have any advice please leave a comment, thanks.

  • Anonymous
    November 04, 2015
    my question is how to use facebook login with android and backend using asp.net web api flotform wih mongoDB database, please can you explain this.

  • Anonymous
    November 10, 2015
    Azure Mobile service with JS backend developing for android. Similar problems as the user @Cash who is two posts above mine. My Azure documentation code with ToDoItems and Facebook authentication was previously working(auth & read write) before I started supplying tokens to the login method. The login method that you used is depreciated now. I am not receiving callbacks but I am not sure if it has anything to do with that. Dug into the doc and tried one of the non depreciated methods that takes a token but does not use a depreciated callback: azure.microsoft.com/.../mobile-services-android-how-to-use-client-library Unfortunately this generates auth errors. So I have two problems, one for each login method. One gives errors and the other does not call back. Same problem? Maybe its my fault involving azure or facebook portal? Everything seems right in my manifest and such. OnActivityResult looks good. If you do any testing please let us know,