From 08291d3388839b84e9a94905c63ad8faeccb0801 Mon Sep 17 00:00:00 2001 From: Wagner Barretto Date: Tue, 29 Jan 2019 15:13:52 -0200 Subject: [PATCH 1/4] Add lite profile scope and get email method --- linkedin_v2/__init__.py | 2 +- linkedin_v2/linkedin.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/linkedin_v2/__init__.py b/linkedin_v2/__init__.py index c434301..fb1bba6 100644 --- a/linkedin_v2/__init__.py +++ b/linkedin_v2/__init__.py @@ -1,2 +1,2 @@ -__version__ = '0.9.5' +__version__ = '0.9.6' VERSION = tuple(map(int, __version__.split('.'))) diff --git a/linkedin_v2/linkedin.py b/linkedin_v2/linkedin.py index 40e1590..add4b4b 100644 --- a/linkedin_v2/linkedin.py +++ b/linkedin_v2/linkedin.py @@ -20,6 +20,7 @@ PERMISSIONS = enum('Permission', COMPANY_ADMIN='rw_company_admin', + LITE_PROFILE='r_liteprofile', BASIC_PROFILE='r_basicprofile', FULL_PROFILE='r_fullprofile', EMAIL_ADDRESS='r_emailaddress', @@ -77,8 +78,8 @@ class LinkedInAuthentication(object): Implements a standard OAuth 2.0 flow that involves redirection for users to authorize the application to access account data. """ - AUTHORIZATION_URL = 'https://www.linkedin.com/uas/oauth2/authorization' - ACCESS_TOKEN_URL = 'https://www.linkedin.com/uas/oauth2/accessToken' + AUTHORIZATION_URL = 'https://www.linkedin.com/oauth/v2/authorization' + ACCESS_TOKEN_URL = 'https://www.linkedin.com/oauth/v2/accessToken' def __init__(self, key, secret, redirect_uri, permissions=None): self.key = key @@ -194,3 +195,9 @@ def get_profile(self, member_id=None, member_url=None, selectors=None, json_response = response.json() json_response.update({'numConnections': connections}) return json_response + + def get_email(self): + url = '%s/emailAddress?q=members&projection=(elements*(handle~))' % ENDPOINTS.BASE + response = self.make_request('GET', url) + raise_for_error(response) + return response.json() From 336f8fbc6d426f29cbadaa50cfcfe2a0ca161f65 Mon Sep 17 00:00:00 2001 From: Wagner Barretto Date: Fri, 1 Feb 2019 14:31:33 -0200 Subject: [PATCH 2/4] Add option to get profile picture through projections --- linkedin_v2/linkedin.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linkedin_v2/linkedin.py b/linkedin_v2/linkedin.py index add4b4b..da1ad2c 100644 --- a/linkedin_v2/linkedin.py +++ b/linkedin_v2/linkedin.py @@ -54,6 +54,10 @@ SHARED='SHAR', VIRAL='VIRL') +PROJECTIONS = enum('Projection', + EXPAND_PROFILE_PICTURE={'projection': '(id,profilePicture(displayImage~:playableStreams))'}, + EXPAND_EMAIL={'q': 'members', 'projection': '(elements*(handle~))'}) + class LinkedInDeveloperAuthentication(object): """ @@ -197,7 +201,7 @@ def get_profile(self, member_id=None, member_url=None, selectors=None, return json_response def get_email(self): - url = '%s/emailAddress?q=members&projection=(elements*(handle~))' % ENDPOINTS.BASE - response = self.make_request('GET', url) + url = '%s/emailAddress' % ENDPOINTS.BASE + response = self.make_request('GET', url, params=PROJECTIONS.EXPAND_EMAIL) raise_for_error(response) return response.json() From 4f7014ac52baddffeefc5d0cbfdf576b9d356b85 Mon Sep 17 00:00:00 2001 From: Wagner Barretto Date: Mon, 4 Feb 2019 08:50:03 -0200 Subject: [PATCH 3/4] Add first and last names to expand profile picture projection --- linkedin_v2/linkedin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linkedin_v2/linkedin.py b/linkedin_v2/linkedin.py index da1ad2c..1f2c8d2 100644 --- a/linkedin_v2/linkedin.py +++ b/linkedin_v2/linkedin.py @@ -55,7 +55,7 @@ VIRAL='VIRL') PROJECTIONS = enum('Projection', - EXPAND_PROFILE_PICTURE={'projection': '(id,profilePicture(displayImage~:playableStreams))'}, + EXPAND_PROFILE_PICTURE={'projection': '(id,firstName,lastName,profilePicture(displayImage~:playableStreams))'}, EXPAND_EMAIL={'q': 'members', 'projection': '(elements*(handle~))'}) From 25eeb7e049c675da05a33f6bbbab8ec34f3273af Mon Sep 17 00:00:00 2001 From: Wagner Barretto Date: Wed, 24 Jul 2019 08:48:35 -0300 Subject: [PATCH 4/4] Update readme --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index 1f9db47..e69a296 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,39 @@ application.get_connections(totals_only=True) } ``` +## Sign In With LinkedIn (lite profile) + +Apps without access to full profile granted by LinkedIn are limited to the sign in with LinkedIn API, check out the [documentation](https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin). Requests to the profile API made by these apps are limited to the lite profile scope, check the [documentation](https://docs.microsoft.com/en-us/linkedin/shared/references/v2/profile/lite-profile?context=linkedin/consumer/context) for more details. + +To authenticate with this mode you need to pass the correct permissions to `LinkedInAuthentication`: + +```python +from linkedin_v2.linkedin import PERMISSIONS + +authentication = linkedin.LinkedInAuthentication(API_KEY, API_SECRET, RETURN_URL, [PERMISSIONS.LITE_PROFILE, PERMISSIONS.EMAIL_ADDRESS]) +``` + +With these permissions, `get_profile` returns only the profile's id, first name, and last name. It is possible to retrieve the profile picture by passing a specific projection to `get_profile`. + +```python +from linkedin_v2.linkedin import PROJECTIONS + +application.get_profile(params=PROJECTIONS.EXPAND_PROFILE_PICTURE) +# Be aware that expanding profile pcture results in a very large response json... +``` + +In order to fetch the profile's email, an extra call is required: + +```python +application.get_email() +{ + "handle": "urn:li:emailAddress:3775708763", + "handle~": { + "emailAddress": "hsimpson@linkedin.com" + } +} +``` + ## Throttle Limits LinkedIn API keys are throttled by default. You should take a look at the [Throttle Limits Documentation](http://developer.linkedin.com/documents/throttle-limits) to get more information about it.