Skip to content

Commit 4bda5a8

Browse files
JakubSzajnaJosh Buker
authored andcommitted
Fix email scope for LinkedIn Provider (#191)
* Used user email address from LinkedIn * Update example user_info_mapping in initializer * Force r_emailaddress in @scope in linkedin provider * Load email only if r_emailaddress is in scope * Adjust initializers Linkedin comment
1 parent f67b989 commit 4bda5a8

File tree

2 files changed

+45
-12
lines changed

2 files changed

+45
-12
lines changed

lib/generators/sorcery/templates/initializer.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,19 @@
8888
#
8989
# config.ca_file =
9090

91+
# Linkedin requires r_emailaddress scope to fetch user's email address.
92+
# You can skip including the email field if you use an intermediary signup form. (using build_from method).
93+
# The r_emailaddress scope is only necessary if you are using the create_from method directly.
94+
#
9195
# config.linkedin.key = ""
9296
# config.linkedin.secret = ""
9397
# config.linkedin.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=linkedin"
94-
# config.linkedin.user_info_mapping = {first_name: "firstName", last_name: "lastName"}
95-
# config.linkedin.scope = "r_basicprofile"
98+
# config.linkedin.user_info_mapping = {
99+
# first_name: 'localizedFirstName',
100+
# last_name: 'localizedLastName',
101+
# email: 'emailAddress'
102+
# }
103+
# config.linkedin.scope = "r_liteprofile r_emailaddress"
96104
#
97105
#
98106
# For information about XING API:

lib/sorcery/providers/linkedin.rb

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,26 @@ module Providers
99
class Linkedin < Base
1010
include Protocols::Oauth2
1111

12-
attr_accessor :auth_url, :scope, :token_url, :user_info_url
12+
attr_accessor :auth_url, :scope, :token_url, :user_info_url, :email_info_url
1313

1414
def initialize
1515
super
1616

17-
@site = 'https://api.linkedin.com'
18-
@auth_url = '/oauth/v2/authorization'
19-
@token_url = '/oauth/v2/accessToken'
20-
@user_info_url = 'https://api.linkedin.com/v2/me'
21-
@scope = 'r_liteprofile'
22-
@state = SecureRandom.hex(16)
17+
@site = 'https://api.linkedin.com'
18+
@auth_url = '/oauth/v2/authorization'
19+
@token_url = '/oauth/v2/accessToken'
20+
@user_info_url = 'https://api.linkedin.com/v2/me'
21+
@email_info_url = 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))'
22+
@scope = 'r_liteprofile r_emailaddress'
23+
@state = SecureRandom.hex(16)
2324
end
2425

2526
def get_user_hash(access_token)
26-
response = access_token.get(user_info_url)
27+
user_info = get_user_info(access_token)
2728

2829
auth_hash(access_token).tap do |h|
29-
h[:user_info] = JSON.parse(response.body)
30-
h[:uid] = h[:user_info]['id']
30+
h[:user_info] = user_info
31+
h[:uid] = h[:user_info]['id']
3132
end
3233
end
3334

@@ -45,6 +46,30 @@ def process_callback(params, _session)
4546

4647
get_access_token(args, token_url: token_url, token_method: :post)
4748
end
49+
50+
def get_user_info(access_token)
51+
response = access_token.get(user_info_url)
52+
user_info = JSON.parse(response.body)
53+
54+
if email_in_scope?
55+
email = fetch_email(access_token)
56+
57+
return user_info.merge(email)
58+
end
59+
60+
user_info
61+
end
62+
63+
def email_in_scope?
64+
scope.include?('r_emailaddress')
65+
end
66+
67+
def fetch_email(access_token)
68+
email_response = access_token.get(email_info_url)
69+
email_info = JSON.parse(email_response.body)['elements'].first
70+
71+
email_info['handle~']
72+
end
4873
end
4974
end
5075
end

0 commit comments

Comments
 (0)