Android LinkedIn OAuth implementation

This article demonstrates Android LinkedIn OAuth implementation using the Scribe library. Implements a sample application “MyConnections”.

“MyConnections” application

Intent of “MyConnections” application is to connect to LinkedIn and display all my connections on the Android platform. Primarily with this application we would be able to demonstrate:-

  1. Android LinkedIn OAuth implementation which is explained in this article.
  2. Android LinkedIn connection implementation using the REST APIs provided by LinkedIn which is explained in a subsequent article.

Register an application as LinkedIn developer

First step in connecting to LinkedIn is to register the application in LinkedIn Developer Portal and get the API key and API secret. For the purpose of this example, I have already registered an application “MyConnections” and have the API key and secret with me.

Scribe OAuth Library

Scribe is a simple OAuth library for Java and supports LinkedIn OAuth APIs out of the box. Scribe is Android ready. More details on Scribe at this location Scribe link. This example uses Scribe to access LinkedIn.

Scribe 1.3.0 is used by this application. Follow these steps to include scribe library to the project.

  1. Create a libs/ folder in the Android application folder and put in scribe-1.3.0.jar file.
  2. Fix the build path of the project to include the scribe library.
  3. Right click on the Android project in eclipse to select “Build Path”.
  4. Now select the sub-option “Configure Build Path”.
  5. Select “Add JARs” and choose the copied library path to insert scribe-1.3.0.jar to the project.

LinkedIn Login Activity

This application has a login activity which has a simple login button. The XML layout of login activity is listed below. We have an authenticate button which initiates the OAuth flow.

<?xml version="1.0" encoding="utf-8"?><RelativeLayout android_layout_width="wrap_content"android:layout_height="fill_parent"android:orientation="vertical" ><Buttonandroid:id="@+id/btAuthenticate"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:text="Login LinkedIn" /></RelativeLayout>

The OnClickListener of authenticate button triggers another activity which performs OAuth with LinkedIn.

LinkedIn OAuth Activity

The OAuth activity has a web view which loads and displays the LinkedIn authentication screen. The XML layout is simple and looks as below.

<?xml version="1.0" encoding="utf-8"?><LinearLayout android_layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><android.webkit.WebView android_id="@+id/linkedin_webview"android:layout_width="fill_parent"android:layout_height="fill_parent"></android.webkit.WebView></LinearLayout>

All the OAuth related work happens in the activity implementation. The OAuth activity has the following API key, secret and callback defined.

final static String APIKEY = "xxxxxxxxxxxx";final static String APISECRET = "xxxxxxxxxxxxxxxx";final static String CALLBACK = "oauth://linkedin";

Scribe has the simple service builder API on which we execute the LinkedIn OAuth workflow.

mService = new ServiceBuilder().provider(LinkedInApi.class).apiKey(APIKEY).apiSecret(APISECRET).callback(CALLBACK).scope("r_basicprofile").scope("rw_nus").build();

Also one important point to note is that to prevent android.os.NetworkOnMainThreadException exception it becomes necessary to exercise the OAuth flow in an AsyncTask.

private class LinkedInAuthTask extends AsyncTask<Void, Void, String> {}

In the doInBackground of AsyncTask we fetch the request token and authorize scribe. This method returns the authURL which is loaded in the web view.

protected String doInBackground(Void... arg0) {// Temporary URLString authURL = "";try {mRequestToken = mService.getRequestToken();authURL = mService.getAuthorizationUrl(mRequestToken);}catch ( OAuthException e ) {e.printStackTrace();return null;}return authURL;}

In the onPostExecute we load the authURL in the web view. At this point user is prompted to key in her LinkedIn credentials and grant access. On receiving the required callback we trade the request token for access token and finish the activity.

@Overrideprotected void onPostExecute(String authURL) {mWebView.setWebViewClient(new WebViewClient() {@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {super.shouldOverrideUrlLoading(view, url);if( url.startsWith("oauth") ) {mWebView.setVisibility(WebView.GONE);final String url1 = url;Thread t1 = new Thread() {public void run() {Uri uri = Uri.parse(url1);String verifier = uri.getQueryParameter("oauth_verifier");Verifier v = new Verifier(verifier);Token accessToken = mService.getAccessToken(mRequestToken, v);Intent intent = new Intent();intent.putExtra("access_token", accessToken.getToken());intent.putExtra("access_secret", accessToken.getSecret());setResult(RESULT_OK, intent);finish();}};t1.start();}return false;}});mWebView.loadUrl(authURL);}

It also becomes necessary to store the access token and access secret to prevent the application from re-prompting the credentials. It is common to store the access token and secrets in shared preferences and reuse for the next launch.

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if ( resultCode == RESULT_OK && requestCode == LINKEDIN_LOGIN_RESULT_CODE ) {String access_token = data.getStringExtra("access_token");String access_secret = data.getStringExtra("access_secret");// Store the tokens in preferences for further useSharedPreferences.Editor editor = mPrefs.edit();editor.putString("linkedin_access_token", access_token);editor.putString("linkedin_access_secret", access_secret);editor.commit();// Start activityIntent intent = new Intent(this, LinkedInListActivity.class);startActivity(intent);}}