Linkedin.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <?php
  2. namespace Overtrue\Socialite\Providers;
  3. use Overtrue\Socialite\User;
  4. /**
  5. * @see https://developer.linkedin.com/docs/oauth2 [Authenticating with OAuth 2.0]
  6. */
  7. class Linkedin extends Base
  8. {
  9. public const NAME = 'linkedin';
  10. protected array $scopes = ['r_liteprofile', 'r_emailaddress'];
  11. protected function getAuthUrl(): string
  12. {
  13. return $this->buildAuthUrlFromBase('https://www.linkedin.com/oauth/v2/authorization');
  14. }
  15. protected function getTokenUrl(): string
  16. {
  17. return 'https://www.linkedin.com/oauth/v2/accessToken';
  18. }
  19. /**
  20. * @param string $code
  21. *
  22. * @return array
  23. */
  24. protected function getTokenFields($code): array
  25. {
  26. return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
  27. }
  28. /**
  29. * @param string $token
  30. * @param array|null $query
  31. *
  32. * @return array
  33. * @throws \GuzzleHttp\Exception\GuzzleException
  34. */
  35. protected function getUserByToken(string $token, ?array $query = []): array
  36. {
  37. $basicProfile = $this->getBasicProfile($token);
  38. $emailAddress = $this->getEmailAddress($token);
  39. return array_merge($basicProfile, $emailAddress);
  40. }
  41. /**
  42. * @param string $token
  43. *
  44. * @return array
  45. * @throws \GuzzleHttp\Exception\GuzzleException
  46. */
  47. protected function getBasicProfile(string $token)
  48. {
  49. $url = 'https://api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))';
  50. $response = $this->getHttpClient()->get($url, [
  51. 'headers' => [
  52. 'Authorization' => 'Bearer '.$token,
  53. 'X-RestLi-Protocol-Version' => '2.0.0',
  54. ],
  55. ]);
  56. return \json_decode($response->getBody(), true) ?? [];
  57. }
  58. /**
  59. * @param string $token
  60. *
  61. * @return array
  62. * @throws \GuzzleHttp\Exception\GuzzleException
  63. */
  64. protected function getEmailAddress(string $token)
  65. {
  66. $url = 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))';
  67. $response = $this->getHttpClient()->get($url, [
  68. 'headers' => [
  69. 'Authorization' => 'Bearer '.$token,
  70. 'X-RestLi-Protocol-Version' => '2.0.0',
  71. ],
  72. ]);
  73. return \json_decode($response->getBody(), true)['elements.0.handle~'] ?? [];
  74. }
  75. /**
  76. * @param array $user
  77. *
  78. * @return \Overtrue\Socialite\User
  79. */
  80. protected function mapUserToObject(array $user): User
  81. {
  82. $preferredLocale = ($user['firstName.preferredLocale.language'] ?? null).'_'.($user['firstName.preferredLocale.country']) ?? null;
  83. $firstName = $user['firstName.localized.'.$preferredLocale] ?? null;
  84. $lastName = $user['lastName.localized.'.$preferredLocale] ?? null;
  85. $name = $firstName.' '.$lastName;
  86. $images = $user['profilePicture.displayImage~.elements'] ?? [];
  87. $avatars = array_filter($images, function ($image) {
  88. return ($image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] ?? 0) === 100;
  89. });
  90. $avatar = array_shift($avatars);
  91. $originalAvatars = array_filter($images, function ($image) {
  92. return ($image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] ?? 0) === 800;
  93. });
  94. $originalAvatar = array_shift($originalAvatars);
  95. return new User([
  96. 'id' => $user['id'] ?? null,
  97. 'nickname' => $name,
  98. 'name' => $name,
  99. 'email' => $user['emailAddress'] ?? null,
  100. 'avatar' => $avatar['identifiers.0.identifier'] ?? null,
  101. 'avatar_original' => $originalAvatar['identifiers.0.identifier'] ?? null,
  102. ]);
  103. }
  104. }