Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement "Login with LinkedIn" with "OAuth 2.0" in Android

In OAuth1.0 "Login with Linkedin" Working fine but before few days Linkedin make some changes in their policy, please refer below link for more detail, https://engineering.linkedin.com/blog/2018/12/developer-program-updates

I also tried some GitHub example and other reference but unfortunately not work for me, I also tried below link but it did not fulfill the exact requirement.

Oauth 2.0 authorization for LinkedIn in Android

You can also refer below link, may it give some result, I also know Linkedin SDK not work here as they declared here, https://developer.linkedin.com/docs/android-sdk We have to call manual URL and open into Webview.

https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin?context=linkedin/consumer/context

I also check 3-4 apps which earlier had LinkedIn support for authentication but now they removed it but I check one app namely "Nuzzel" in that I found Linked in authentication and it's working fine so it means there is some way to do it properly. Nuzzel App Link:- https://play.google.com/store/apps/details?id=com.nuzzel.android&hl=en_GB

Thanks

like image 225
Kunal Shah Avatar asked Feb 04 '19 10:02

Kunal Shah


3 Answers

After a little effort I got it working, but implementing it every time you start a new project will waste a lot of time.

So I created a light weight library for the same.

Just add the dependency to your app level build.gradle file

dependencies {
    implementation 'com.shantanudeshmukh:linkedinsdk:1.0.0'
}

Initiate Login Request.

LinkedInBuilder.getInstance(MainActivity.this)
        .setClientID("<YOUR_CLIENT_ID_HERE>")
        .setClientSecret("<YOUR_CLIENT_SECRET_HERE>")
        .setRedirectURI("<YOUR_REDIRECT_URL_HERE>")
        .authenticate(LINKEDIN_REQUEST_CODE);

Handle the response:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == LINKEDIN_REQUEST_CODE && data != null) {
        if (resultCode == RESULT_OK) {
            //Successfully signed in
            LinkedInUser user = data.getParcelableExtra("social_login");

            //acessing user info
            Log.i("LinkedInLogin", user.getFirstName());

        } else {

            if (data.getIntExtra("err_code", 0) == LinkedInBuilder.ERROR_USER_DENIED) {
                //Handle : user denied access to account

            } else if (data.getIntExtra("err_code", 0) == LinkedInBuilder.ERROR_FAILED) {
                    
                //Handle : Error in API : see logcat output for details
                Log.e("LINKEDIN ERROR", data.getStringExtra("err_message"));
            }
        }
    }
}

I'm using this library in multiple production apps, so I'll try to keep it as updated as possible. You can find other details here.

like image 144
Shantanu Avatar answered Oct 18 '22 17:10

Shantanu


I created a small library to implement LinkedIn Authentication via OAuth2

Library - https://github.com/Sumudu-Sahan/LinkedInManager

Steps

  1. Add the below maven dependency to your project level build.gradle file

    allprojects { repositories { ... maven { url 'https://jitpack.io' } } }

  2. add the below maven dependency to your app level build.gradle file

    dependencies { implementation 'com.github.Sumudu-Sahan:LinkedInManager:1.00.02' }

  3. Inherit your activity, fragment from LinkedInManagerResponse

    public class MainActivity extends AppCompatActivity implements LinkedInManagerResponse

  4. Initiate the LinkedInRequestManager object instance for login process

    LinkedInRequestManager linkedInRequestManager = new LinkedInRequestManager(Activity, LinkedInManagerResponse, "CLIENT ID", "CLIENT SECRET", "REDIRECTION URL");

  5. Start Authenticate with below statement

linkedInRequestManager.showAuthenticateView(LinkedInRequestManager.MODE_BOTH_OPTIONS);

Available Modes

LinkedInRequestManager.MODE_EMAIL_ADDRESS_ONLY
LinkedInRequestManager.MODE_LITE_PROFILE_ONLY
LinkedInRequestManager.MODE_BOTH_OPTIONS
like image 21
Sumudu Sahan Weerasuriya Avatar answered Oct 18 '22 16:10

Sumudu Sahan Weerasuriya


Here is my code, to implement sign in with "0Auth2.0"

class NewLinkedInIntegration extends Activity {

    private static final String API_KEY = "your client id";
    private static final String SECRET_KEY = "your secret key";
    private static final String STATE = "DCEeFWf45A53sdfKef424";

    private static final String REDIRECT_URI = "your url";
    private static final String AUTHORIZATION_URL = "https://www.linkedin.com/uas/oauth2/authorization";

    private static final String ACCESS_TOKEN_URL = "https://www.linkedin.com/uas/oauth2/accessToken";

    private static final String SECRET_KEY_PARAM = "client_secret";

    private static final String RESPONSE_TYPE_PARAM = "response_type";

    private static final String GRANT_TYPE_PARAM = "grant_type";

    private static final String GRANT_TYPE = "authorization_code";

    private static final String RESPONSE_TYPE_VALUE = "code";

    private static final String CLIENT_ID_PARAM = "client_id";

    private static final String STATE_PARAM = "state";
    private static final String REDIRECT_URI_PARAM = "redirect_uri";
    private static final String QUESTION_MARK = "?";
    private static final String AMPERSAND = "&";
    private static final String EQUALS = "=";

    String profileUrl = "https://api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))";
    String accessToken;
    String linkedInUserEmailAddress;
    SharedPreferences sharedPreferences;
    String emailAddress = "https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))";
    private WebView webView;
    TransparentDialog mProgressBarHandler;
    private ProgressDialog pd;
    String deviceId, location, country;
    String linkedInUserId, linkedInUserFirstName, linkedInUserLastName, linkedInUserProfile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_linked);
        //get the webView from the layout
        webView = (WebView) findViewById(R.id.main_activity_web_view);
        deviceId = getIntent().getStringExtra("deviceId");
        location = getIntent().getStringExtra("location");
        country = getIntent().getStringExtra("country");
        //Request focus for the webview
        webView.requestFocus(View.FOCUS_DOWN);
        webView.clearHistory();
        webView.clearCache(true);
        sharedPreferences = MyApplication.preference;
        pd = ProgressDialog.show(this, "", "Loadingg...", true);
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                //This method will be executed each time a page finished loading.
                //The only we do is dismiss the progressDialog, in case we are showing any.
                if (pd != null && pd.isShowing()) {
                    pd.dismiss();
                }
            }

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String authorizationUrl) {
                //This method will be called when the Auth proccess redirect to our RedirectUri.
                //We will check the url looking for our RedirectUri.
                if (authorizationUrl.startsWith(REDIRECT_URI)) {
                    Log.i("Authorize", "");
                    Uri uri = Uri.parse(authorizationUrl);
                    //We take from the url the authorizationToken and the state token. We have to check that the state token returned by the Service is the same we sent.
                    //If not, that means the request may be a result of CSRF and must be rejected.
                    String stateToken = uri.getQueryParameter(STATE_PARAM);
                    if (stateToken == null || !stateToken.equals(STATE)) {
                        Log.e("Authorize", "State token doesn't match");
                        return true;
                    }

                    //If the user doesn't allow authorization to our application, the authorizationToken Will be null.
                    String authorizationToken = uri.getQueryParameter(RESPONSE_TYPE_VALUE);
                    if (authorizationToken == null) {
                        Log.i("Authorize", "The user doesn't allow authorization.");
                        return true;
                    }
                    Log.i("Authorize", "Auth token received: " + authorizationToken);

                    //Generate URL for requesting Access Token
                    String accessTokenUrl = getAccessTokenUrl(authorizationToken);
                    //We make the request in a AsyncTask
                    new PostRequestAsyncTask().execute(accessTokenUrl);

                } else {
                    //Default behaviour
                    Log.i("Authorize", "Redirecting to: " + authorizationUrl);
                    webView.loadUrl(authorizationUrl);
                }
                return true;
            }
        });
        String authUrl = getAuthorizationUrl();
        Log.i("Authorize", "Loading Auth Url: " + authUrl);
        webView.loadUrl(authUrl);
    }

    /**
     * Method that generates the url for get the access token from the Service
     *
     * @return Url
     */
    private static String getAccessTokenUrl(String authorizationToken) {
        return ACCESS_TOKEN_URL
                + QUESTION_MARK
                + GRANT_TYPE_PARAM + EQUALS + GRANT_TYPE
                + AMPERSAND
                + RESPONSE_TYPE_VALUE + EQUALS + authorizationToken
                + AMPERSAND
                + CLIENT_ID_PARAM + EQUALS + API_KEY
                + AMPERSAND
                + REDIRECT_URI_PARAM + EQUALS + REDIRECT_URI
                + AMPERSAND
                + SECRET_KEY_PARAM + EQUALS + SECRET_KEY;
    }

    /**
     * Method that generates the url for get the authorization token from the Service
     *
     * @return Url
     */
    private static String getAuthorizationUrl() {
        return AUTHORIZATION_URL
                + QUESTION_MARK + RESPONSE_TYPE_PARAM + EQUALS + RESPONSE_TYPE_VALUE
                + AMPERSAND + CLIENT_ID_PARAM + EQUALS + API_KEY
                + AMPERSAND + STATE_PARAM + EQUALS + STATE
                + AMPERSAND + REDIRECT_URI_PARAM + EQUALS + REDIRECT_URI + "&scope=r_liteprofile%20r_emailaddress%20w_member_social";
    }


    private class PostRequestAsyncTask extends AsyncTask<String, Void, Boolean> {

        @Override
        protected void onPreExecute() {
            pd = ProgressDialog.show(NewLinkedInIntegration.this, "", "Loading", true);
        }

        @Override
        protected Boolean doInBackground(String... urls) {
            if (urls.length > 0) {
                String url = urls[0];
                HttpClient httpClient = new DefaultHttpClient();
                HttpPost httpost = new HttpPost(url);
                try {
                    HttpResponse response = httpClient.execute(httpost);
                    if (response != null) {
                        //If status is OK 200
                        if (response.getStatusLine().getStatusCode() == 200) {
                            String result = EntityUtils.toString(response.getEntity());
                            JSONObject resultJson = new JSONObject(result);
                            int expiresIn = resultJson.has("expires_in") ? resultJson.getInt("expires_in") : 0;
                            String accessToken = resultJson.has("access_token") ? resultJson.getString("access_token") : null;
                            Log.e("Tokenm", "" + accessToken);
                            if (expiresIn > 0 && accessToken != null) {
                                Log.i("Authorize", "This is the access Token: " + accessToken + ". It will expires in " + expiresIn + " secs");
                                Calendar calendar = Calendar.getInstance();
                                calendar.add(Calendar.SECOND, expiresIn);
                                long expireDate = calendar.getTimeInMillis();
                                SharedPreferences preferences = NewLinkedInIntegration.this.getSharedPreferences("user_info", 0);
                                SharedPreferences.Editor editor = preferences.edit();
                                editor.putLong("expires", expireDate);
                                editor.putString("accessToken", accessToken);
                                editor.commit();

                                return true;
                            }
                        }
                    }
                } catch (IOException e) {
                    Log.e("Authorize", "Error Http response " + e.getLocalizedMessage());
                } catch (ParseException e) {
                    Log.e("Authorize", "Error Parsing Http response " + e.getLocalizedMessage());
                } catch (JSONException e) {
                    Log.e("Authorize", "Error Parsing Http response " + e.getLocalizedMessage());
                }
            }
            return false;
        }

        @Override
        protected void onPostExecute(Boolean status) {
            if (pd != null && pd.isShowing()) {
                pd.dismiss();
            }
            if (status) {
                SharedPreferences preferences = NewLinkedInIntegration.this.getSharedPreferences("user_info", 0);
                accessToken = preferences.getString("accessToken", null);
                try {
                    if (accessToken != null) {
                        new GetProfileRequestAsyncTask().execute(profileUrl);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public void sendGetRequest(String urlString, String accessToken) throws Exception {
        URL url = new URL(urlString);
        HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
        con.setRequestMethod("GET");
        con.setRequestProperty("Authorization", "Bearer " + accessToken);
        con.setRequestProperty("cache-control", "no-cache");
        con.setRequestProperty("X-Restli-Protocol-Version", "2.0.0");
        BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
        StringBuilder jsonString = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            jsonString.append(line);
        }
        JSONObject jsonObject = new JSONObject(jsonString.toString());
        Log.d("Complete json object", jsonObject.toString());
        try {
            linkedInUserId = jsonObject.getString("id");
            String country = jsonObject.getJSONObject("firstName").getJSONObject("preferredLocale").getString("country");
            String language = jsonObject.getJSONObject("firstName").getJSONObject("preferredLocale").getString("language");
            String getFirstnameKey = language + "_" + country;
            linkedInUserFirstName = jsonObject.getJSONObject("firstName").getJSONObject("localized").getString(getFirstnameKey);
            linkedInUserLastName = jsonObject.getJSONObject("firstName").getJSONObject("localized").getString(getFirstnameKey);
            linkedInUserProfile = jsonObject.getJSONObject("profilePicture").getJSONObject("displayImage~").getJSONArray("elements").getJSONObject(0).getJSONArray("identifiers").getJSONObject(0).getString("identifier");

        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    private void sendGetRequestForEmail(String urlString, String accessToken) throws Exception {
        URL url = new URL(urlString);
        HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
        con.setRequestMethod("GET");
        con.setRequestProperty("Authorization", "Bearer " + accessToken);
        con.setRequestProperty("cache-control", "no-cache");
        con.setRequestProperty("X-Restli-Protocol-Version", "2.0.0");
        BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
        StringBuilder jsonString = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            jsonString.append(line);
        }
        JSONObject jsonObject = new JSONObject(jsonString.toString());
        linkedInUserEmailAddress = jsonObject.getJSONArray("elements").getJSONObject(0).getJSONObject("handle~").getString("emailAddress");
        Log.d("email json object", jsonObject.toString());
        sendRequestToServerForLinkwedInIntegration();


    }

    public void sendRequestToServerForLinkwedInIntegration() {

        if (AppUtils.isInternetOn(NewLinkedInIntegration.this)) {

            JSONObject userJsonObject = new JSONObject();
            try {
                userJsonObject.put(NetworkKeys.EMAIL, linkedInUserEmailAddress);
                userJsonObject.put(NetworkKeys.USERNAME, linkedInUserFirstName + " " + linkedInUserLastName);
                userJsonObject.put(NetworkKeys.CONTACTNO, "");
                userJsonObject.put(NetworkKeys.UID, linkedInUserId);
                userJsonObject.put(NetworkKeys.PROVIDER, "LinkedIn");
                userJsonObject.put(NetworkKeys.IMAGE, linkedInUserProfile);
                userJsonObject.put(NetworkKeys.DEVICE_TOKEN, deviceId);
                userJsonObject.put(NetworkKeys.LOCATION, location);
                userJsonObject.put(NetworkKeys.COUNTRY, country);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            String url = Constants.WebServices.SOCIAL_MEDIA_LOGIN;
            CallWebService.getInstance(NewLinkedInIntegration.this, true).hitJSONObjectVolleyWebServicemanageclubdetailsWithoutAccessToken(Request.Method.POST, url, deviceId, userJsonObject, new CallBackInterfaceVolley() {
                @Override
                public void onJsonObjectSuccess(JSONObject object) {
                    pd.dismiss();
                    try {
                        boolean success = object.getBoolean(NetworkKeys.SUCCESS);

                        if (success) {
                            JSONObject userInfoJsonObject = object.getJSONObject(NetworkKeys.USERJSONOBJECT);
                            String userId = userInfoJsonObject.getString(NetworkKeys.SIGN_IN_USERID);
                            String userEmail = userInfoJsonObject.getString(NetworkKeys.SIGN_IN_USER_EMAIL);
                            String userImage = userInfoJsonObject.getString(NetworkKeys.SIGN_IN_USER_IMAGE);
                            String userName = userInfoJsonObject.getString(NetworkKeys.SIGN_IN_USER_NAME);
                            String userCity = userInfoJsonObject.getString(NetworkKeys.USER_CITY);
                            String contactNo = userInfoJsonObject.getString(NetworkKeys.CONTACT_NO);
                            String userCountry = userInfoJsonObject.getString(NetworkKeys.USER_COUNTRY);
                            String isNotificationOn = userInfoJsonObject.getString(NetworkKeys.ISNOTIFICATION);
                            String userLocation = userInfoJsonObject.getString(NetworkKeys.SIGN_IN_USER_LOCATION);
                            String signInUserType = userInfoJsonObject.getString(NetworkKeys.SIGN_IN_USER_PROVIDER);
                            String userAuthToken = userInfoJsonObject.getString(NetworkKeys.SIGN_IN_USER_AUTHTOKEN);
                            SharedPreferences.Editor editor = sharedPreferences.edit();
                            editor.putString(NetworkKeys.SIGN_IN_USERID, userId);
                            editor.putString(NetworkKeys.SIGN_IN_USER_EMAIL, userEmail);
                            editor.putString(NetworkKeys.SIGN_IN_USER_IMAGE, userImage);
                            editor.putString(NetworkKeys.SIGN_IN_USER_NAME, userName);
                            editor.putString(NetworkKeys.USER_CITY, userCity);
                            editor.putString(NetworkKeys.USER_COUNTRY, userCountry);
                            editor.putString(NetworkKeys.SIGN_IN_USER_MOBILE, contactNo);
                            editor.putString(NetworkKeys.SIGN_IN_USER_LOCATION, userLocation);
                            editor.putString(NetworkKeys.SIGN_IN_USER_PROVIDER, signInUserType);
                            editor.putString(NetworkKeys.ISNOTIFICATION, isNotificationOn);
                            editor.putString(NetworkKeys.SIGN_IN_USER_AUTHTOKEN, userAuthToken);
                            editor.putBoolean(NetworkKeys.IS_USER_LOGIN_FROM_SOCIAL_MEDIA, true);
                            editor.putBoolean(NetworkKeys.SIGN_IN_USER_SUCCESSFULLY, true);
                            editor.apply();
                            Intent intent = new Intent(NewLinkedInIntegration.this, CardSelctionActivity.class);
                            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                            finish();
                        } else {
                            pd.dismiss();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onJsonArrarSuccess(JSONArray array) {

                }

                @Override
                public void onFailure(String str) {
                    pd.dismiss();
                }
            });
        } else {
            AppUtils.showToast(NewLinkedInIntegration.this, getResources().getString(R.string.internet_connection));
        }
    }


    private class GetProfileRequestAsyncTask extends AsyncTask<String, Void, JSONObject> {

        @Override
        protected void onPreExecute() {
            pd = ProgressDialog.show(NewLinkedInIntegration.this, "", "Loading..", true);
        }

        @Override
        protected JSONObject doInBackground(String... urls) {
            if (urls.length > 0) {
                try {
                    sendGetRequest(profileUrl, accessToken);
                    sendGetRequestForEmail(emailAddress, accessToken);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        @Override
        protected void onPostExecute(JSONObject data) {
            if (pd != null && pd.isShowing()) {
                pd.dismiss();
            }
            if (data != null) {

                try {
                    String welcomeTextString = String.format("Welcome %1$s %2$s, You are a %3$s", data.getString("firstName"), data.getString("lastName"), data.getString("headline"));

                } catch (JSONException e) {
                    Log.e("Authorize", "Error Parsing json " + e.getLocalizedMessage());
                }
            }
        }

    }
}

If you want further assistance go to below link explained how to sign in with Linkedin with auth 2.0. Have a look

linkedin integration with oauth20 -v2-in-complete implementation ain android

like image 23
Aryan Dhankar Avatar answered Oct 18 '22 17:10

Aryan Dhankar