@@ -48,13 +48,13 @@ class LinkedinOAuth2(BaseOAuth2):
4848 name = "linkedin-oauth2"
4949 AUTHORIZATION_URL = "https://www.linkedin.com/oauth/v2/authorization"
5050 ACCESS_TOKEN_URL = "https://www.linkedin.com/oauth/v2/accessToken"
51- USER_DETAILS_URL = "https://api.linkedin.com/v2/userinfo ?projection=({projection})"
51+ USER_DETAILS_URL = "https://api.linkedin.com/v2/me ?projection=({projection})"
5252 USER_EMAILS_URL = (
5353 "https://api.linkedin.com/v2/emailAddress"
5454 "?q=members&projection=(elements*(handle~))"
5555 )
5656 REDIRECT_STATE = False
57- DEFAULT_SCOPE = ["email" , "profile" , "openid " ]
57+ DEFAULT_SCOPE = ["r_liteprofile " ]
5858 EXTRA_DATA = [
5959 ("id" , "id" ),
6060 ("expires_in" , "expires" ),
@@ -65,7 +65,14 @@ class LinkedinOAuth2(BaseOAuth2):
6565 ]
6666
6767 def user_details_url (self ):
68- return self .USER_DETAILS_URL
68+ # use set() since LinkedIn fails when values are duplicated
69+ fields_selectors = list (
70+ {"id" , "firstName" , "lastName" , * self .setting ("FIELD_SELECTORS" , [])}
71+ )
72+ # user sort to ease the tests URL mocking
73+ fields_selectors .sort ()
74+ fields_selectors = "," .join (fields_selectors )
75+ return self .USER_DETAILS_URL .format (projection = fields_selectors )
6976
7077 def user_emails_url (self ):
7178 return self .USER_EMAILS_URL
@@ -75,10 +82,10 @@ def user_data(self, access_token, *args, **kwargs):
7582 self .user_details_url (), headers = self .user_data_headers (access_token )
7683 )
7784
78- if "email " in set (self .setting ("FIELD_SELECTORS" , [])):
85+ if "emailAddress " in set (self .setting ("FIELD_SELECTORS" , [])):
7986 emails = self .email_data (access_token , * args , ** kwargs )
8087 if emails :
81- response ["email " ] = emails [0 ]
88+ response ["emailAddress " ] = emails [0 ]
8289
8390 return response
8491
@@ -88,20 +95,38 @@ def email_data(self, access_token, *args, **kwargs):
8895 )
8996 email_addresses = []
9097 for element in response .get ("elements" , []):
91- email_address = element .get ("handle~" , {}).get ("email " )
98+ email_address = element .get ("handle~" , {}).get ("emailAddress " )
9299 email_addresses .append (email_address )
93100 return list (filter (None , email_addresses ))
94101
95102 def get_user_details (self , response ):
96103 """Return user details from Linkedin account"""
97- response = self .user_data (access_token = response ["access_token" ])
104+
105+ def get_localized_name (name ):
106+ """
107+ FirstName & Last Name object
108+ {
109+ 'localized': {
110+ 'en_US': 'Smith'
111+ },
112+ 'preferredLocale': {
113+ 'country': 'US',
114+ 'language': 'en'
115+ }
116+ }
117+ :return the localizedName from the lastName object
118+ """
119+ locale = "{}_{}" .format (
120+ name ["preferredLocale" ]["language" ], name ["preferredLocale" ]["country" ]
121+ )
122+ return name ["localized" ].get (locale , "" )
123+
98124 fullname , first_name , last_name = self .get_user_names (
99- first_name = response ["given_name" ] ,
100- last_name = response ["family_name" ] ,
125+ first_name = get_localized_name ( response ["firstName" ]) ,
126+ last_name = get_localized_name ( response ["lastName" ]) ,
101127 )
102- email = response .get ("email " , "" )
128+ email = response .get ("emailAddress " , "" )
103129 return {
104- "id" : response .get ("sub" , "" ),
105130 "username" : first_name + last_name ,
106131 "fullname" : fullname ,
107132 "first_name" : first_name ,
0 commit comments