Skip to content

Commit c97a42c

Browse files
Merge pull request #44 from workstory/v2
Upgrade gem to work with LinkedIn API v2 (r_liteprofile)
2 parents f31c69d + 3d8d338 commit c97a42c

File tree

6 files changed

+151
-110
lines changed

6 files changed

+151
-110
lines changed

README.md

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
A LinkedIn OAuth2 strategy for OmniAuth.
66

7-
For more details, read the LinkedIn documentation: https://developer.linkedin.com/documents/authentication
7+
For more details, read the LinkedIn documentation: https://developer.linkedin.com/docs/oauth2
88

99
## Installation
1010

@@ -22,6 +22,8 @@ Or install it yourself as:
2222

2323
## Upgrading
2424

25+
This version is a major upgrade to the LinkedIn API version 2. As such, it switches from the soon to be no longer available `r_basicprofile` to `r_liteprofile`. This results in a much limited set of data that we can get from LinkedIn.
26+
2527
Previous versions of this gem used the provider name `:linkedin_oauth2`. In order to provide a cleaner upgrade path for users who were previously using the OAuth 1.0 omniauth adapter for LinkedIn [https://github.com/skorks/omniauth-linkedin], this has been renamed to just `:linkedin`.
2628

2729
Users who are upgrading from previous versions of this gem may need to update their Omniauth and/or Devise configurations to use the shorter provider name.
@@ -43,42 +45,38 @@ You can now access the OmniAuth LinkedIn OAuth2 URL: `/auth/linkedin`.
4345
## Granting Member Permissions to Your Application
4446

4547
With the LinkedIn API, you have the ability to specify which permissions you want users to grant your application.
46-
For more details, read the LinkedIn documentation: https://developer.linkedin.com/documents/authentication
48+
For more details, read the LinkedIn documentation: https://developer.linkedin.com/docs/oauth2
4749

4850
By default, omniauth-linkedin-oauth2 requests the following permissions:
4951

50-
'r_basicprofile r_emailaddress'
52+
'r_liteprofile r_emailaddress'
5153

5254
You can configure the scope option:
5355

5456
```ruby
55-
provider :linkedin, ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'], :scope => 'r_fullprofile r_emailaddress r_network'
57+
provider :linkedin, ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'], :scope => 'r_literofile'
5658
```
5759

5860
## Profile Fields
5961

6062
When specifying which permissions you want to users to grant to your application, you will probably want to specify the array of fields that you want returned in the omniauth hash. The list of default fields is as follows:
6163

6264
```ruby
63-
['id', 'email-address', 'first-name', 'last-name', 'headline', 'location', 'industry', 'picture-url', 'public-profile-url']
65+
['id', 'first-name', 'last-name', 'picture-url', 'email-address']
6466
```
6567

66-
Here's an example of a possible configuration where the fields returned from the API are: id, email-address, first-name and last-name.
68+
Here's an example of a possible configuration where the fields returned from the API are: id, first-name and last-name.
6769

6870
```ruby
69-
provider :linkedin, ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'], :fields => ['id', 'email-address', 'first-name', 'last-name']
71+
provider :linkedin, ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'], :fields => ['id', 'first-name', 'last-name']
7072
```
7173

72-
To see a complete list of available fields, consult the LinkedIn documentation at: https://developer.linkedin.com/documents/profile-fields
73-
74-
## Other Options
75-
76-
* `secure_image_url` - Set to `true` to use https for the profile picture url. Default is `false`.
74+
To see a complete list of available fields, consult the LinkedIn documentation at: https://developer.linkedin.com/docs/fields
7775

7876
## Contributing
7977

80-
1. Fork it
81-
2. Create your feature branch (`git checkout -b my-new-feature`)
82-
3. Commit your changes (`git commit -am 'Add some feature'`)
83-
4. Push to the branch (`git push origin my-new-feature`)
84-
5. Create new Pull Request
78+
1. Fork it
79+
2. Create your feature branch (`git checkout -b my-new-feature`)
80+
3. Commit your changes (`git commit -am 'Add some feature'`)
81+
4. Push to the branch (`git push origin my-new-feature`)
82+
5. Create new Pull Request
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module OmniAuth
22
module LinkedInOAuth2
3-
VERSION = "0.2.5"
3+
VERSION = '1.0.0'
44
end
55
end

lib/omniauth/strategies/linkedin.rb

Lines changed: 87 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,34 @@
33
module OmniAuth
44
module Strategies
55
class LinkedIn < OmniAuth::Strategies::OAuth2
6-
# Give your strategy a name.
76
option :name, 'linkedin'
87

9-
# This is where you pass the options you would pass when
10-
# initializing your consumer from the OAuth gem.
118
option :client_options, {
129
:site => 'https://api.linkedin.com',
1310
:authorize_url => 'https://www.linkedin.com/oauth/v2/authorization?response_type=code',
1411
:token_url => 'https://www.linkedin.com/oauth/v2/accessToken'
1512
}
1613

17-
option :scope, 'r_basicprofile r_emailaddress'
18-
option :fields, ['id', 'email-address', 'first-name', 'last-name', 'headline', 'location', 'industry', 'picture-url', 'public-profile-url']
14+
option :scope, 'r_liteprofile r_emailaddress'
15+
option :fields, ['id', 'first-name', 'last-name', 'picture-url', 'email-address']
1916

20-
# These are called after authentication has succeeded. If
21-
# possible, you should try to set the UID without making
22-
# additional calls (if the user id is returned with the token
23-
# or as a URI parameter). This may not be possible with all
24-
# providers.
25-
uid { raw_info['id'] }
17+
uid do
18+
raw_info['id']
19+
end
2620

2721
info do
2822
{
29-
:name => user_name,
30-
:email => raw_info['emailAddress'],
31-
:nickname => user_name,
32-
:first_name => raw_info['firstName'],
33-
:last_name => raw_info['lastName'],
34-
:location => raw_info['location'],
35-
:description => raw_info['headline'],
36-
:image => raw_info['pictureUrl'],
37-
:urls => {
38-
'public_profile' => raw_info['publicProfileUrl']
39-
}
23+
:email => email_address,
24+
:first_name => localized_field('firstName'),
25+
:last_name => localized_field('lastName'),
26+
:picture_url => picture_url
4027
}
4128
end
4229

4330
extra do
44-
{ 'raw_info' => raw_info }
31+
{
32+
'raw_info' => raw_info
33+
}
4534
end
4635

4736
def callback_url
@@ -52,28 +41,93 @@ def callback_url
5241

5342
def access_token
5443
::OAuth2::AccessToken.new(client, oauth2_access_token.token, {
55-
:mode => :query,
56-
:param_name => 'oauth2_access_token',
5744
:expires_in => oauth2_access_token.expires_in,
5845
:expires_at => oauth2_access_token.expires_at
5946
})
6047
end
6148

6249
def raw_info
63-
@raw_info ||= access_token.get("/v1/people/~:(#{option_fields.join(',')})?format=json").parsed
50+
@raw_info ||= access_token.get(profile_endpoint).parsed
6451
end
6552

6653
private
6754

68-
def option_fields
69-
fields = options.fields
70-
fields.map! { |f| f == "picture-url" ? "picture-url;secure=true" : f } if !!options[:secure_image_url]
71-
fields
55+
def email_address
56+
if options.fields.include? 'email-address'
57+
fetch_email_address
58+
parse_email_address
59+
end
60+
end
61+
62+
def fetch_email_address
63+
@email_address_response ||= access_token.get(email_address_endpoint).parsed
64+
end
65+
66+
def parse_email_address
67+
return unless email_address_available?
68+
69+
@email_address_response['elements'].first['handle~']['emailAddress']
70+
end
71+
72+
def email_address_available?
73+
@email_address_response['elements'] &&
74+
@email_address_response['elements'].is_a?(Array) &&
75+
@email_address_response['elements'].first &&
76+
@email_address_response['elements'].first['handle~']
77+
end
78+
79+
def fields_mapping
80+
{
81+
'id' => 'id',
82+
'first-name' => 'firstName',
83+
'last-name' => 'lastName',
84+
'picture-url' => 'profilePicture(displayImage~:playableStreams)'
85+
}
86+
end
87+
88+
def fields
89+
options.fields.each.with_object([]) do |field, result|
90+
result << fields_mapping[field] if fields_mapping.has_key? field
91+
end
92+
end
93+
94+
def localized_field field_name
95+
return unless localized_field_available? field_name
96+
97+
raw_info[field_name]['localized'][field_locale(field_name)]
98+
end
99+
100+
def field_locale field_name
101+
"#{ raw_info[field_name]['preferredLocale']['language'] }_" \
102+
"#{ raw_info[field_name]['preferredLocale']['country'] }"
103+
end
104+
105+
def localized_field_available? field_name
106+
raw_info[field_name] && raw_info[field_name]['localized']
107+
end
108+
109+
def picture_url
110+
return unless picture_available?
111+
112+
picture_references.last['identifiers'].first['identifier']
113+
end
114+
115+
def picture_available?
116+
raw_info['profilePicture'] &&
117+
raw_info['profilePicture']['displayImage~'] &&
118+
picture_references
119+
end
120+
121+
def picture_references
122+
raw_info['profilePicture']['displayImage~']['elements']
123+
end
124+
125+
def email_address_endpoint
126+
'/v2/emailAddress?q=members&projection=(elements*(handle~))'
72127
end
73128

74-
def user_name
75-
name = "#{raw_info['firstName']} #{raw_info['lastName']}".strip
76-
name.empty? ? nil : name
129+
def profile_endpoint
130+
"/v2/me?projection=(#{ fields.join(',') })"
77131
end
78132
end
79133
end

omniauth-linkedin-oauth2.gemspec

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@ Gem::Specification.new do |gem|
1818
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
1919
gem.require_paths = ["lib"]
2020

21-
gem.add_runtime_dependency 'omniauth', '~> 1.0'
2221
gem.add_runtime_dependency 'omniauth-oauth2'
2322

24-
gem.add_development_dependency 'bundler', '~> 1.3'
23+
gem.add_development_dependency 'bundler'
2524
gem.add_development_dependency 'rake'
2625

27-
gem.add_development_dependency 'rspec', '~> 3.0'
26+
gem.add_development_dependency 'rspec'
2827
gem.add_development_dependency 'simplecov'
2928
end

0 commit comments

Comments
 (0)