omniauth-yahoo-oauth2 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 784ac84ce174a7e01cc6ff2093f87258edaffa52
4
- data.tar.gz: 6383b98740bbac0c5b93787bb869306c828710de
2
+ SHA256:
3
+ metadata.gz: d5a2c23bd49d42781032387a982ba92dcf388a5946b3a75ab70e33b711959e36
4
+ data.tar.gz: 20b3e2e88fb855dd62a562b840a5259534da733e3a8728d683f85554db6b2cb9
5
5
  SHA512:
6
- metadata.gz: 499b6375e10ac27c860f80ae59e77b21aefb0a0958e6936355207f8d85fa79637b4ab6abe3145d5020f57b80be08213ffece4369f24e3f0647500508877d0204
7
- data.tar.gz: 1d635f2e19db108e51d11f0303da8f0852212064aa1e3cd31a4eb1ff0f6ed589313beac37c5f69c253bafcd3b226aaf5388bab1b02ea0fe147442b1886c1c1db
6
+ metadata.gz: 0f00d924baf2b6bda0c11c3d2bbd331d7afab7f82cc3fb953102adabbf5186f4ee3fab3c1f7a0cfcb87cde1a9300eea27a1f5f77b8f3e4ec7860b6ffb35941a6
7
+ data.tar.gz: e640145bfa89799591d54ec4d78414cbc066e3161c2c1ab662e6ab861ff5f1f3b737a469d2b5b646bd21376b3e06ccf8fa15c7adbbdac05c80a0792514c77f4f
data/README.md CHANGED
@@ -1,56 +1,67 @@
1
1
  ## omniauth-yahoo-oauth2 ##
2
2
 
3
- An unofficial, hastily-written Oauth2 OmniAuth strategy for Yahoo. Uses the authorization flow described at https://developer.yahoo.com/oauth2/guide/flows_authcode/.
3
+ An unofficial, hastily-written Oauth2 OmniAuth strategy for Yahoo. Uses the
4
+ authorization flow described at
5
+ https://developer.yahoo.com/oauth2/guide/flows_authcode/.
4
6
 
5
7
  Built using https://github.com/intridea/omniauth-oauth2.
6
8
 
7
9
  ## Setup ##
8
10
  `gem install omniauth-yahoo-oauth2`
9
11
 
10
- Create an app at https://developer.yahoo.com/apps to get a Yahoo client ID and secret.
12
+ Create an app at https://developer.yahoo.com/apps to get a Yahoo client ID and
13
+ secret.
11
14
 
12
15
  ## Usage ##
13
16
  ```ruby
14
17
  # In an initializer
15
18
  Rails.application.config.middleware.use OmniAuth::Builder do
16
- provider :yahoo_oauth2, yahoo_client_id, yahoo_secret,
17
- name: 'yahoo'
19
+ provider :yahoo_oauth2, yahoo_client_id, yahoo_secret, name: 'yahoo'
18
20
  end
19
21
  ```
20
22
 
21
23
  See https://github.com/intridea/omniauth for Omniauth instructions.
22
24
 
23
25
  ## Notes ##
24
- OmniAuth doesn't currently have built-in support for Basic Authentication for retrieving OAuth tokens, so `YahooOauth2#build_access_token` handles this inline.
25
26
 
26
- Yahoo returns an access_token, a refresh_token, and an expiration time for the access_token. They are available in the authentication hash in the callback:
27
+ OmniAuth doesn't currently have built-in support for Basic Authentication for
28
+ retrieving OAuth2 tokens, so `YahooOauth2::Client` overrides
29
+ `OAuth2::Client#get_token`. Yahoo also requires `redirect_uri` to be set when
30
+ refreshing the `access_token`, so `YahooOauth2::AccessToken` overrides
31
+ `OAuth2::AccessToken#refresh!` to handle that.
32
+
33
+ As with other OAuth2 providers, Yahoo returns an `access_token`, a
34
+ `refresh_token`, and an expiration time for the `access_token`. They are
35
+ available in the credentials hash in the callback:
36
+
37
+ ```ruby
38
+ credentials = request.env.fetch('omniauth.auth').fetch(:credentials)
39
+ tokens_hash = {
40
+ access_token: credentials[:token],
41
+ refresh_token: credentials[:refresh_token],
42
+ expires_at: credentials[:expires_at]
43
+ }
44
+ ```
45
+
46
+ They should be saved to your application's database. You can use the
47
+ `access_token` directly or use `YahooOauth2::AccessToken` for requests:
27
48
 
28
49
  ```ruby
29
- auth_info = request.env['omniauth.auth']
30
- access_token = auth_info[:credentials][:token]
31
- refresh_token = auth_info[:credentials][:refresh_token]
32
- expires_at = auth_info[:credentials][:expires_at]
50
+ client = YahooOauth2::Client.new(YAHOO_CLIENT_ID, YAHOO_SECRET)
51
+ token = YahooOauth2::AccessToken.from_hash(client, tokens_hash)
52
+ token.get(
53
+ "https://social.yahooapis.com/v1/user/#{uid}/profile?format=json"
54
+ ).parsed
33
55
  ```
34
56
 
35
- You can use the refresh_token to generate new access tokens:
57
+ And to refresh the access token once it has expired:
36
58
 
37
59
  ```ruby
38
- require 'oauth2'
39
- require 'base64'
40
-
41
- oauth_client = OAuth2::Client.new(YAHOO_CLIENT_ID, YAHOO_SECRET, {
42
- site: 'https://api.login.yahoo.com',
43
- authorize_url: '/oauth2/request_auth',
44
- token_url: '/oauth2/get_token',
45
- })
46
-
47
- auth = "Basic #{Base64.strict_encode64("#{YAHOO_CLIENT_ID}:#{YAHOO_SECRET}")}"
48
-
49
- new_token = oauth_client.get_token({
50
- redirect_uri: YOUR_CALLBACK_URL,
51
- refresh_token: YOUR_REFRESH_TOKEN,
52
- grant_type: 'refresh_token',
53
- headers: { 'Authorization' => auth } })
60
+ old_token = YahooOauth2::AccessToken.from_hash(client, tokens_hash)
61
+ if old_token.expired?
62
+ new_token = old_token.refresh!
63
+ new_token.to_hash # => update your database with this
64
+ end
54
65
  ```
55
66
 
56
67
  ## TODO ##
@@ -1 +1 @@
1
- require File.join('omniauth', 'yahoo_oauth2')
1
+ require 'omniauth/yahoo_oauth2'
@@ -1,49 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jwt"
1
4
  require 'omniauth/strategies/oauth2'
2
- require 'base64'
3
5
 
4
6
  module OmniAuth
5
7
  module Strategies
6
8
  class YahooOauth2 < OmniAuth::Strategies::OAuth2
7
- option :name, 'yahoo_oauth2'
8
-
9
+
10
+ OPEN_ID_CONNECT_SCOPES = "openid,profile,email"
11
+
12
+ ALLOWED_ISSUERS = %w[
13
+ https://api.login.yahoo.com
14
+ api.login.yahoo.com
15
+ login.yahoo.com
16
+ ].freeze
17
+
18
+ option :name, 'yahoo'
19
+
20
+ option :userinfo_url, "/openid/v1/userinfo"
21
+
9
22
  option :client_options, {
10
- site: 'https://api.login.yahoo.com',
11
- authorize_url: '/oauth2/request_auth',
12
- token_url: '/oauth2/get_token',
23
+ site: "https://api.login.yahoo.com",
24
+ authorize_url: "/oauth2/request_auth",
25
+ token_url: "/oauth2/get_token",
13
26
  }
14
27
 
15
- uid { access_token.params['xoauth_yahoo_guid'] }
28
+ option :skip_jwt, false
29
+ option :jwt_leeway, 300
30
+
31
+ option :authorize_params, {
32
+ response_type: 'code',
33
+ }
34
+
35
+ option :authorize_options, %i[
36
+ language
37
+ login_hint
38
+ max_age
39
+ prompt
40
+ redirect_uri
41
+ scope
42
+ state
43
+ ]
44
+
45
+ uid { raw_info['sub'] }
16
46
 
17
47
  info do
18
- {
19
- name: raw_info['profile']['nickname'],
20
- nickname: raw_info['profile']['nickname'],
21
- gender: raw_info['profile']['gender'],
22
- language: raw_info['profile']['lang'],
23
- location: raw_info['profile']['location'],
48
+ prune!({
49
+ name: raw_info["name"],
50
+ email: verified_email,
51
+ unverified_email: raw_info['email'],
52
+ email_verified: raw_info["email_verified"],
53
+ first_name: raw_info["given_name"],
54
+ last_name: raw_info["family_name"],
55
+ nickname: raw_info["nickname"],
56
+ gender: raw_info["gender"],
57
+ locale: raw_info['locale'],
58
+ image: raw_info['picture'],
59
+ phone: raw_info["phone_number"],
60
+ phone_verified: raw_info["phone_number_verified"],
24
61
  urls: {
25
- image: raw_info['profile']['image']['imageUrl'],
26
- profile: raw_info['profile']['profileUrl']
27
- }
28
- }
29
- end
30
-
31
- def build_access_token
32
- verifier = request.params['code']
33
-
34
- auth = "Basic #{Base64.strict_encode64("#{options.client_id}:#{options.client_secret}")}"
35
-
36
- token = client.get_token(
37
- { redirect_uri: callback_url, code: verifier, grant_type: 'authorization_code', headers: { 'Authorization' => auth } }.
38
- merge(token_params.to_hash(symbolize_keys: true)), deep_symbolize(options.auth_token_params))
39
-
40
- token
41
- end
42
-
62
+ profile: raw_info['profile'],
63
+ website: raw_info['website'],
64
+ },
65
+ })
66
+ end
67
+
68
+ # n.b. renamed raw_info to userinfo. Userinfo is part of the OIDc standard.
69
+ extra do
70
+ hash = {}
71
+ hash[:userinfo] = raw_info unless skip_info?
72
+ hash[:id_token] = access_token["id_token"]
73
+ hash[:id_info] = decode_info_token
74
+ prune! hash
75
+ end
76
+
43
77
  def raw_info
44
- raw_info_url = "https://social.yahooapis.com/v1/user/#{uid}/profile?format=json"
45
- @raw_info ||= access_token.get(raw_info_url).parsed
78
+ @raw_info ||= access_token.get(userinfo_url).parsed
79
+ end
80
+
81
+ private
82
+
83
+ # This follows the example in omniauth-google-oauth2.
84
+ #
85
+ # Probably better to set the redirect_uri as a client option when creating
86
+ # the client, because OAuth2::Client knows how to handle it, but that
87
+ # requires updating OmniAuth::Strategies::OAuth2.
88
+ def callback_url
89
+ options[:redirect_uri] || (full_host + script_name + callback_path)
90
+ end
91
+
92
+ def userinfo_url
93
+ options.client_options.site + options.userinfo_url
94
+ end
95
+
96
+ # This is copied from the omniauth-google-oauth2 gem
97
+ def verified_email
98
+ raw_info['email_verified'] ? raw_info['email'] : nil
99
+ end
100
+
101
+ # This is copied from the omniauth-google-oauth2 gem
102
+ def prune!(hash)
103
+ hash.delete_if do |_, v|
104
+ prune!(v) if v.is_a?(Hash)
105
+ v.nil? || (v.respond_to?(:empty?) && v.empty?)
106
+ end
46
107
  end
108
+
109
+ # super saves SecureRandom state to session and merges authorize_options
110
+ #
111
+ # This follows the example in omniauth-google-oauth2 and
112
+ # merges any request param with the same name as an authorize_option.
113
+ # It then saves state to the session (in case it was overwritten).
114
+ #
115
+ # Probably the better way to handle this is to build it into "options_for"
116
+ # and have another option (e.g. authorize_request_params).
117
+ def authorize_params
118
+ super.tap do |params|
119
+ options[:authorize_options].each do |k|
120
+ unless [nil, ''].include?(request.params[k.to_s])
121
+ params[k] = request.params[k.to_s]
122
+ end
123
+ session['omniauth.state'] = params[:state] if params[:state]
124
+ end
125
+ end
126
+ end
127
+
128
+ # This is copied from the omniauth-google-oauth2 gem
129
+ def decode_info_token
130
+ unless options[:skip_jwt] || access_token['id_token'].nil?
131
+ decoded = ::JWT.decode(access_token['id_token'], nil, false).first
132
+
133
+ # We have to manually verify the claims because the third parameter to
134
+ # JWT.decode is false since no verification key is provided.
135
+ ::JWT::Verify.verify_claims(decoded,
136
+ verify_iss: true,
137
+ iss: ALLOWED_ISSUERS,
138
+ verify_aud: true,
139
+ aud: options.client_id,
140
+ verify_sub: false,
141
+ verify_expiration: true,
142
+ verify_not_before: true,
143
+ verify_iat: true,
144
+ verify_jti: false,
145
+ leeway: options[:jwt_leeway])
146
+
147
+ decoded
148
+ end
149
+ end
150
+
47
151
  end
48
152
  end
49
153
  end
@@ -1 +1 @@
1
- require File.join('omniauth', 'strategies', 'yahoo_oauth2')
1
+ require 'omniauth/strategies/yahoo_oauth2'
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module YahooOauth2
3
- VERSION = '1.1.0'
3
+ VERSION = '1.2.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-yahoo-oauth2
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amir Manji
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-06 00:00:00.000000000 Z
11
+ date: 2020-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: omniauth
@@ -86,8 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
86
  - !ruby/object:Gem::Version
87
87
  version: '0'
88
88
  requirements: []
89
- rubyforge_project:
90
- rubygems_version: 2.2.2
89
+ rubygems_version: 3.0.3
91
90
  signing_key:
92
91
  specification_version: 4
93
92
  summary: A Yahoo OAuth2 strategy for OmniAuth.