From 001fcfabdd99540ed1d09d477762af3a485d0cd3 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 18 Dec 2018 12:21:53 +0100 Subject: [PATCH] Fix LinkedInProvider for new API LinkedIn has suddenly stopped supported the previous endpoint we used to retrieve user profile information so we need to use the new API for authenticating users. Fixes https://github.com/laravel/socialite/issues/309 --- src/Two/LinkedInProvider.php | 79 ++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/src/Two/LinkedInProvider.php b/src/Two/LinkedInProvider.php index f8ac6cd4..83231193 100644 --- a/src/Two/LinkedInProvider.php +++ b/src/Two/LinkedInProvider.php @@ -11,7 +11,7 @@ class LinkedInProvider extends AbstractProvider implements ProviderInterface * * @var array */ - protected $scopes = ['r_basicprofile', 'r_emailaddress']; + protected $scopes = ['r_liteprofile', 'r_emailaddress']; /** * The separating character for the requested scopes. @@ -20,17 +20,6 @@ class LinkedInProvider extends AbstractProvider implements ProviderInterface */ protected $scopeSeparator = ' '; - /** - * The fields that are included in the profile. - * - * @var array - */ - protected $fields = [ - 'id', 'first-name', 'last-name', 'formatted-name', - 'email-address', 'headline', 'location', 'industry', - 'public-profile-url', 'picture-url', 'picture-urls::(original)', - ]; - /** * {@inheritdoc} */ @@ -63,14 +52,26 @@ protected function getTokenFields($code) */ protected function getUserByToken($token) { - $fields = implode(',', $this->fields); + $basicProfile = $this->getBasicProfile($token); + $emailAddress = $this->getEmailAddress($token); - $url = 'https://api.linkedin.com/v1/people/~:('.$fields.')'; + return array_merge($basicProfile, $emailAddress); + } + + /** + * Get the basic profile fields for the user. + * + * @param string $token + * @return array + */ + protected function getBasicProfile($token) + { + $url = 'https://api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))'; $response = $this->getHttpClient()->get($url, [ 'headers' => [ - 'x-li-format' => 'json', 'Authorization' => 'Bearer '.$token, + 'X-RestLi-Protocol-Version' => '2.0.0', ], ]); @@ -78,30 +79,46 @@ protected function getUserByToken($token) } /** - * {@inheritdoc} + * Get the email address for the user. + * + * @param string $token + * @return array */ - protected function mapUserToObject(array $user) + protected function getEmailAddress($token) { - return (new User)->setRaw($user)->map([ - 'id' => $user['id'], - 'nickname' => null, - 'name' => Arr::get($user, 'formattedName'), - 'email' => Arr::get($user, 'emailAddress'), - 'avatar' => Arr::get($user, 'pictureUrl'), - 'avatar_original' => Arr::get($user, 'pictureUrls.values.0'), + $url = 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))'; + + $response = $this->getHttpClient()->get($url, [ + 'headers' => [ + 'Authorization' => 'Bearer '.$token, + 'X-RestLi-Protocol-Version' => '2.0.0', + ], ]); + + return json_decode($response->getBody(), true)['elements'][0]['handle~']; } /** - * Set the user fields to request from LinkedIn. - * - * @param array $fields - * @return $this + * {@inheritdoc} */ - public function fields(array $fields) + protected function mapUserToObject(array $user) { - $this->fields = $fields; + $name = Arr::get($user, 'firstName.localized.en_US').' '.Arr::get($user, 'lastName.localized.en_US'); + $images = Arr::get($user, 'profilePicture.displayImage~.elements'); + $avatar = Arr::first(Arr::where($images, function ($image) { + return $image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] === 100; + })); + $originalAvatar = Arr::first(Arr::where($images, function ($image) { + return $image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] === 800; + })); - return $this; + return (new User)->setRaw($user)->map([ + 'id' => $user['id'], + 'nickname' => null, + 'name' => $name, + 'email' => Arr::get($user, 'emailAddress'), + 'avatar' => Arr::get($avatar, 'identifiers.0.identifier'), + 'avatar_original' => Arr::get($originalAvatar, 'identifiers.0.identifier'), + ]); } }