Skip to content

Commit 17a8a7f

Browse files
authored
fix: Revert LinkedIn OAuth2 (#1147)
* Revert LinkedIn OAuth2 * fix: RUF005 Consider iterable unpacking instead of concatenation * fix: C405 Unnecessary list literal (rewrite as a set literal)
1 parent 345ad5f commit 17a8a7f

File tree

2 files changed

+48
-22
lines changed

2 files changed

+48
-22
lines changed

social_core/backends/linkedin.py

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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,

social_core/tests/backends/test_linkedin.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,24 @@ def test_invalid_nonce(self):
4141

4242

4343
class BaseLinkedinTest:
44-
user_data_url = "https://api.linkedin.com/v2/userinfo"
44+
user_data_url = "https://api.linkedin.com/v2/me?projection=(firstName,id,lastName)"
4545
expected_username = "FooBar"
4646
access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"})
4747

4848
# Reference:
49-
# https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self
50-
# -serve/sign-in-with-linkedin-v2#response-body-schema
49+
# https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self
50+
# -serve/sign-in-with-linkedin?context=linkedin/consumer/context#api-request
5151
user_data_body = json.dumps(
5252
{
53-
"sub": "782bbtaQ",
54-
"name": "FooBar",
55-
"given_name": "Foo",
56-
"family_name": "Bar",
57-
"picture": "https://media.licdn-ei.com/dms/image/C5F03AQHqK8v7tB1HCQ/profile-displayphoto-shrink_100_100/0/",
58-
"locale": "en-US",
59-
"email": "[email protected]",
60-
"email_verified": True,
53+
"id": "1010101010",
54+
"firstName": {
55+
"localized": {"en_US": "Foo"},
56+
"preferredLocale": {"country": "US", "language": "en"},
57+
},
58+
"lastName": {
59+
"localized": {"en_US": "Bar"},
60+
"preferredLocale": {"country": "US", "language": "en"},
61+
},
6162
}
6263
)
6364

0 commit comments

Comments
 (0)