oauth2 1.4.4 → 1.4.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -2
  3. data/CODE_OF_CONDUCT.md +105 -46
  4. data/README.md +8 -3
  5. data/lib/oauth2/access_token.rb +8 -7
  6. data/lib/oauth2/authenticator.rb +1 -1
  7. data/lib/oauth2/client.rb +60 -14
  8. data/lib/oauth2/mac_token.rb +10 -2
  9. data/lib/oauth2/response.rb +5 -3
  10. data/lib/oauth2/strategy/assertion.rb +3 -3
  11. data/lib/oauth2/strategy/password.rb +2 -2
  12. data/lib/oauth2/version.rb +9 -3
  13. data/spec/helper.rb +37 -0
  14. data/spec/oauth2/access_token_spec.rb +216 -0
  15. data/spec/oauth2/authenticator_spec.rb +84 -0
  16. data/spec/oauth2/client_spec.rb +506 -0
  17. data/spec/oauth2/mac_token_spec.rb +117 -0
  18. data/spec/oauth2/response_spec.rb +90 -0
  19. data/spec/oauth2/strategy/assertion_spec.rb +58 -0
  20. data/spec/oauth2/strategy/auth_code_spec.rb +107 -0
  21. data/spec/oauth2/strategy/base_spec.rb +5 -0
  22. data/spec/oauth2/strategy/client_credentials_spec.rb +69 -0
  23. data/spec/oauth2/strategy/implicit_spec.rb +26 -0
  24. data/spec/oauth2/strategy/password_spec.rb +55 -0
  25. data/spec/oauth2/version_spec.rb +23 -0
  26. metadata +38 -41
  27. data/.document +0 -5
  28. data/.gitignore +0 -19
  29. data/.jrubyrc +0 -1
  30. data/.rspec +0 -2
  31. data/.rubocop.yml +0 -80
  32. data/.rubocop_rspec.yml +0 -26
  33. data/.rubocop_todo.yml +0 -15
  34. data/.ruby-version +0 -1
  35. data/.travis.yml +0 -87
  36. data/CONTRIBUTING.md +0 -18
  37. data/Gemfile +0 -40
  38. data/Rakefile +0 -45
  39. data/gemfiles/jruby_1.7.gemfile +0 -11
  40. data/gemfiles/jruby_9.0.gemfile +0 -7
  41. data/gemfiles/jruby_9.1.gemfile +0 -3
  42. data/gemfiles/jruby_9.2.gemfile +0 -3
  43. data/gemfiles/jruby_head.gemfile +0 -3
  44. data/gemfiles/ruby_1.9.gemfile +0 -11
  45. data/gemfiles/ruby_2.0.gemfile +0 -6
  46. data/gemfiles/ruby_2.1.gemfile +0 -6
  47. data/gemfiles/ruby_2.2.gemfile +0 -3
  48. data/gemfiles/ruby_2.3.gemfile +0 -3
  49. data/gemfiles/ruby_2.4.gemfile +0 -3
  50. data/gemfiles/ruby_2.5.gemfile +0 -3
  51. data/gemfiles/ruby_2.6.gemfile +0 -9
  52. data/gemfiles/ruby_2.7.gemfile +0 -9
  53. data/gemfiles/ruby_head.gemfile +0 -9
  54. data/gemfiles/truffleruby.gemfile +0 -3
  55. data/oauth2.gemspec +0 -52
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b97977a64f018ee795bce70e2b670bac5d50c731c8f206f1ff9d074c29be1192
4
- data.tar.gz: 3d11d9da6bd69267f571e01077e776f07deae6d0411e71493061faa22bbfd694
3
+ metadata.gz: 74ca15f9b1935885fe123c9b0801b9f0605c1bfa904bebe371d201a61b559f31
4
+ data.tar.gz: 3b719ec6748493cba5112dfca8ebff22b13c0c9690330d4422f9d81b1abf5185
5
5
  SHA512:
6
- metadata.gz: 2931c2d95bb544b4af8ad3415c4be029733042cb1e959c11427344e062bcd59fab97293371241843cca9b7ba92b1ef7ef148f687f91ba36df5d4c94cf6dd9c5d
7
- data.tar.gz: 9db9d4e0bb93eff4c83e567abcf1c6c3b59023d1d8eaccb3f7e2762809e2ac6278288c56a3aafc3f812ceb946c6a84840d65172428e89dda9b608ee248676c55
6
+ metadata.gz: 7ec3c9c311effac7f8864c2dc3d7332761ee6a986f2924adec3b77620abe3dc63984d1c01e9ca0a1283907a5b2ba23ee31dfd4bd630fa7d803fba116ba1e652d
7
+ data.tar.gz: 1e1d37d5953bdd7e03e13f697648e56afdb63ea54bbdbaee7ee229302149c5047c533a15d6498a355ef78d17d991d79ce8f94fe8728229431e3fad5c3132a9ad
data/CHANGELOG.md CHANGED
@@ -1,9 +1,22 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## [unreleased]
4
+ ## unreleased
5
5
 
6
- - no changes yet
6
+ ## [1.4.7] - 2021-03-18
7
+
8
+ - [#541](https://github.com/oauth-xx/oauth2/pull/541) - Backport fix to expires_at handling [#533](https://github.com/oauth-xx/oauth2/pull/533) to 1-4-stable branch. (@dobon)
9
+
10
+ ## [1.4.6] - 2021-03-18
11
+
12
+ - [#540](https://github.com/oauth-xx/oauth2/pull/540) - Add VERSION constant (@pboling)
13
+ - [#537](https://github.com/oauth-xx/oauth2/pull/537) - Fix crash in OAuth2::Client#get_token (@anderscarling)
14
+ - [#538](https://github.com/oauth-xx/oauth2/pull/538) - Remove reliance on globally included OAuth2 in tests for version 1.4 (@anderscarling)
15
+
16
+ ## [1.4.5] - 2021-03-18
17
+
18
+ - [#535](https://github.com/oauth-xx/oauth2/pull/535) - Compatibility with range of supported Ruby OpenSSL versions, Rubocop updates, Github Actions (@pboling)
19
+ - [#518](https://github.com/oauth-xx/oauth2/pull/518) - Add extract_access_token option to OAuth2::Client (@jonspalmer)
7
20
 
8
21
  ## [1.4.4] - 2020-02-12
9
22
 
data/CODE_OF_CONDUCT.md CHANGED
@@ -1,74 +1,133 @@
1
+
1
2
  # Contributor Covenant Code of Conduct
2
3
 
3
4
  ## Our Pledge
4
5
 
5
- In the interest of fostering an open and welcoming environment, we as
6
- contributors and maintainers pledge to making participation in our project and
7
- our community a harassment-free experience for everyone, regardless of age, body
8
- size, disability, ethnicity, gender identity and expression, level of experience,
9
- nationality, personal appearance, race, religion, or sexual identity and
10
- orientation.
6
+ We as members, contributors, and leaders pledge to make participation in our
7
+ community a harassment-free experience for everyone, regardless of age, body
8
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
9
+ identity and expression, level of experience, education, socio-economic status,
10
+ nationality, personal appearance, race, religion, or sexual identity
11
+ and orientation.
12
+
13
+ We pledge to act and interact in ways that contribute to an open, welcoming,
14
+ diverse, inclusive, and healthy community.
11
15
 
12
16
  ## Our Standards
13
17
 
14
- Examples of behavior that contributes to creating a positive environment
15
- include:
18
+ Examples of behavior that contributes to a positive environment for our
19
+ community include:
16
20
 
17
- * Using welcoming and inclusive language
18
- * Being respectful of differing viewpoints and experiences
19
- * Gracefully accepting constructive criticism
20
- * Focusing on what is best for the community
21
- * Showing empathy towards other community members
21
+ * Demonstrating empathy and kindness toward other people
22
+ * Being respectful of differing opinions, viewpoints, and experiences
23
+ * Giving and gracefully accepting constructive feedback
24
+ * Accepting responsibility and apologizing to those affected by our mistakes,
25
+ and learning from the experience
26
+ * Focusing on what is best not just for us as individuals, but for the
27
+ overall community
22
28
 
23
- Examples of unacceptable behavior by participants include:
29
+ Examples of unacceptable behavior include:
24
30
 
25
- * The use of sexualized language or imagery and unwelcome sexual attention or
26
- advances
27
- * Trolling, insulting/derogatory comments, and personal or political attacks
31
+ * The use of sexualized language or imagery, and sexual attention or
32
+ advances of any kind
33
+ * Trolling, insulting or derogatory comments, and personal or political attacks
28
34
  * Public or private harassment
29
- * Publishing others' private information, such as a physical or electronic
30
- address, without explicit permission
35
+ * Publishing others' private information, such as a physical or email
36
+ address, without their explicit permission
31
37
  * Other conduct which could reasonably be considered inappropriate in a
32
38
  professional setting
33
39
 
34
- ## Our Responsibilities
40
+ ## Enforcement Responsibilities
35
41
 
36
- Project maintainers are responsible for clarifying the standards of acceptable
37
- behavior and are expected to take appropriate and fair corrective action in
38
- response to any instances of unacceptable behavior.
42
+ Community leaders are responsible for clarifying and enforcing our standards of
43
+ acceptable behavior and will take appropriate and fair corrective action in
44
+ response to any behavior that they deem inappropriate, threatening, offensive,
45
+ or harmful.
39
46
 
40
- Project maintainers have the right and responsibility to remove, edit, or
41
- reject comments, commits, code, wiki edits, issues, and other contributions
42
- that are not aligned to this Code of Conduct, or to ban temporarily or
43
- permanently any contributor for other behaviors that they deem inappropriate,
44
- threatening, offensive, or harmful.
47
+ Community leaders have the right and responsibility to remove, edit, or reject
48
+ comments, commits, code, wiki edits, issues, and other contributions that are
49
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
50
+ decisions when appropriate.
45
51
 
46
52
  ## Scope
47
53
 
48
- This Code of Conduct applies both within project spaces and in public spaces
49
- when an individual is representing the project or its community. Examples of
50
- representing a project or community include using an official project e-mail
51
- address, posting via an official social media account, or acting as an appointed
52
- representative at an online or offline event. Representation of a project may be
53
- further defined and clarified by project maintainers.
54
+ This Code of Conduct applies within all community spaces, and also applies when
55
+ an individual is officially representing the community in public spaces.
56
+ Examples of representing our community include using an official e-mail address,
57
+ posting via an official social media account, or acting as an appointed
58
+ representative at an online or offline event.
54
59
 
55
60
  ## Enforcement
56
61
 
57
62
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at peter.boling@gmail.com. All
59
- complaints will be reviewed and investigated and will result in a response that
60
- is deemed necessary and appropriate to the circumstances. The project team is
61
- obligated to maintain confidentiality with regard to the reporter of an incident.
62
- Further details of specific enforcement policies may be posted separately.
63
+ reported to the community leaders responsible for enforcement at
64
+ [INSERT CONTACT METHOD].
65
+ All complaints will be reviewed and investigated promptly and fairly.
66
+
67
+ All community leaders are obligated to respect the privacy and security of the
68
+ reporter of any incident.
69
+
70
+ ## Enforcement Guidelines
71
+
72
+ Community leaders will follow these Community Impact Guidelines in determining
73
+ the consequences for any action they deem in violation of this Code of Conduct:
74
+
75
+ ### 1. Correction
76
+
77
+ **Community Impact**: Use of inappropriate language or other behavior deemed
78
+ unprofessional or unwelcome in the community.
79
+
80
+ **Consequence**: A private, written warning from community leaders, providing
81
+ clarity around the nature of the violation and an explanation of why the
82
+ behavior was inappropriate. A public apology may be requested.
83
+
84
+ ### 2. Warning
63
85
 
64
- Project maintainers who do not follow or enforce the Code of Conduct in good
65
- faith may face temporary or permanent repercussions as determined by other
66
- members of the project's leadership.
86
+ **Community Impact**: A violation through a single incident or series
87
+ of actions.
88
+
89
+ **Consequence**: A warning with consequences for continued behavior. No
90
+ interaction with the people involved, including unsolicited interaction with
91
+ those enforcing the Code of Conduct, for a specified period of time. This
92
+ includes avoiding interactions in community spaces as well as external channels
93
+ like social media. Violating these terms may lead to a temporary or
94
+ permanent ban.
95
+
96
+ ### 3. Temporary Ban
97
+
98
+ **Community Impact**: A serious violation of community standards, including
99
+ sustained inappropriate behavior.
100
+
101
+ **Consequence**: A temporary ban from any sort of interaction or public
102
+ communication with the community for a specified period of time. No public or
103
+ private interaction with the people involved, including unsolicited interaction
104
+ with those enforcing the Code of Conduct, is allowed during this period.
105
+ Violating these terms may lead to a permanent ban.
106
+
107
+ ### 4. Permanent Ban
108
+
109
+ **Community Impact**: Demonstrating a pattern of violation of community
110
+ standards, including sustained inappropriate behavior, harassment of an
111
+ individual, or aggression toward or disparagement of classes of individuals.
112
+
113
+ **Consequence**: A permanent ban from any sort of public interaction within
114
+ the community.
67
115
 
68
116
  ## Attribution
69
117
 
70
- This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at [http://contributor-covenant.org/version/1/4][version]
118
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
119
+ version 2.0, available at
120
+ [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
121
+
122
+ Community Impact Guidelines were inspired by
123
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
124
+
125
+ For answers to common questions about this code of conduct, see the FAQ at
126
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available
127
+ at [https://www.contributor-covenant.org/translations][translations].
72
128
 
73
- [homepage]: http://contributor-covenant.org
74
- [version]: http://contributor-covenant.org/version/1/4/
129
+ [homepage]: https://www.contributor-covenant.org
130
+ [v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
131
+ [Mozilla CoC]: https://github.com/mozilla/diversity
132
+ [FAQ]: https://www.contributor-covenant.org/faq
133
+ [translations]: https://www.contributor-covenant.org/translations
data/README.md CHANGED
@@ -4,6 +4,9 @@ If you need the readme for a released version of the gem please find it below:
4
4
 
5
5
  | Version | Release Date | Readme |
6
6
  |----------|--------------|----------------------------------------------------------|
7
+ | 1.4.7 | Mar 18, 2021 | https://github.com/oauth-xx/oauth2/blob/v1.4.7/README.md |
8
+ | 1.4.6 | Mar 18, 2021 | https://github.com/oauth-xx/oauth2/blob/v1.4.6/README.md |
9
+ | 1.4.5 | Mar 18, 2021 | https://github.com/oauth-xx/oauth2/blob/v1.4.5/README.md |
7
10
  | 1.4.4 | Feb 12, 2020 | https://github.com/oauth-xx/oauth2/blob/v1.4.4/README.md |
8
11
  | 1.4.3 | Jan 29, 2020 | https://github.com/oauth-xx/oauth2/blob/v1.4.3/README.md |
9
12
  | 1.4.2 | Oct 1, 2019 | https://github.com/oauth-xx/oauth2/blob/v1.4.2/README.md |
@@ -20,6 +23,7 @@ If you need the readme for a released version of the gem please find it below:
20
23
  [![Total Downloads](https://img.shields.io/gem/dt/oauth2.svg)][gem]
21
24
  [![Downloads Today](https://img.shields.io/gem/rt/oauth2.svg)][gem]
22
25
  [![Build Status](https://travis-ci.org/oauth-xx/oauth2.svg?branch=1-4-stable)][travis]
26
+ [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Foauth-xx%2Foauth2%2Fbadge&style=flat)][github-actions]
23
27
  [![Test Coverage](https://api.codeclimate.com/v1/badges/688c612528ff90a46955/test_coverage)][codeclimate-coverage]
24
28
  [![Maintainability](https://api.codeclimate.com/v1/badges/688c612528ff90a46955/maintainability)][codeclimate-maintainability]
25
29
  [![Depfu](https://badges.depfu.com/badges/6d34dc1ba682bbdf9ae2a97848241743/count.svg)][depfu]
@@ -30,6 +34,7 @@ If you need the readme for a released version of the gem please find it below:
30
34
 
31
35
  [gem]: https://rubygems.org/gems/oauth2
32
36
  [travis]: http://travis-ci.org/oauth-xx/oauth2
37
+ [github-actions]: https://actions-badge.atrox.dev/oauth-xx/oauth2/goto
33
38
  [coveralls]: https://coveralls.io/r/oauth-xx/oauth2
34
39
  [codeclimate-maintainability]: https://codeclimate.com/github/oauth-xx/oauth2/maintainability
35
40
  [codeclimate-coverage]: https://codeclimate.com/github/oauth-xx/oauth2/test_coverage
@@ -79,7 +84,7 @@ client.auth_code.authorize_url(:redirect_uri => 'http://localhost:8080/oauth2/ca
79
84
  # => "https://example.org/oauth/authorization?response_type=code&client_id=client_id&redirect_uri=http://localhost:8080/oauth2/callback"
80
85
 
81
86
  token = client.auth_code.get_token('authorization_code_value', :redirect_uri => 'http://localhost:8080/oauth2/callback', :headers => {'Authorization' => 'Basic some_password'})
82
- response = token.get('/api/resource', :params => { 'query_foo' => 'bar' })
87
+ response = token.get('/api/resource', :params => {'query_foo' => 'bar'})
83
88
  response.class.name
84
89
  # => OAuth2::Response
85
90
  ```
@@ -166,7 +171,7 @@ implementations:
166
171
 
167
172
  * Ruby 2.2 - Support ends with version 2.x series
168
173
  * Ruby 2.3 - Support ends with version 3.x series
169
- - [JRuby 9.1][jruby-9.1] (targets MRI v2.3)
174
+ - [JRuby 9.1][jruby-9.1] (targets MRI v2.3)
170
175
  * Ruby 2.4 - Support ends with version 4.x series
171
176
  * Ruby 2.5 - Support ends with version 5.x series
172
177
  - [JRuby 9.2][jruby-9.2] (targets MRI v2.5)
@@ -230,7 +235,7 @@ spec.add_dependency 'oauth2', '~> 1.4'
230
235
 
231
236
  ## Development
232
237
 
233
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
238
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
234
239
 
235
240
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
236
241
 
@@ -3,6 +3,7 @@ module OAuth2
3
3
  attr_reader :client, :token, :expires_in, :expires_at, :params
4
4
  attr_accessor :options, :refresh_token
5
5
 
6
+ # Should these methods be deprecated?
6
7
  class << self
7
8
  # Initializes an AccessToken from a Hash
8
9
  #
@@ -48,9 +49,9 @@ module OAuth2
48
49
  @expires_in &&= @expires_in.to_i
49
50
  @expires_at &&= convert_expires_at(@expires_at)
50
51
  @expires_at ||= Time.now.to_i + @expires_in if @expires_in
51
- @options = {:mode => opts.delete(:mode) || :header,
52
+ @options = {:mode => opts.delete(:mode) || :header,
52
53
  :header_format => opts.delete(:header_format) || 'Bearer %s',
53
- :param_name => opts.delete(:param_name) || 'access_token'}
54
+ :param_name => opts.delete(:param_name) || 'access_token'}
54
55
  @params = opts
55
56
  end
56
57
 
@@ -81,6 +82,7 @@ module OAuth2
81
82
  # @note options should be carried over to the new AccessToken
82
83
  def refresh!(params = {})
83
84
  raise('A refresh_token is not available') unless refresh_token
85
+
84
86
  params[:grant_type] = 'refresh_token'
85
87
  params[:refresh_token] = refresh_token
86
88
  new_token = @client.get_token(params)
@@ -149,7 +151,7 @@ module OAuth2
149
151
 
150
152
  private
151
153
 
152
- def configure_authentication!(opts) # rubocop:disable MethodLength, Metrics/AbcSize
154
+ def configure_authentication!(opts) # rubocop:disable Metrics/AbcSize
153
155
  case options[:mode]
154
156
  when :header
155
157
  opts[:headers] ||= {}
@@ -171,10 +173,9 @@ module OAuth2
171
173
  end
172
174
 
173
175
  def convert_expires_at(expires_at)
174
- expires_at_i = expires_at.to_i
175
- return expires_at_i if expires_at_i > Time.now.utc.to_i
176
- return Time.parse(expires_at).to_i if expires_at.is_a?(String)
177
- expires_at_i
176
+ Time.iso8601(expires_at.to_s).to_i
177
+ rescue ArgumentError
178
+ expires_at.to_i
178
179
  end
179
180
  end
180
181
  end
@@ -49,7 +49,7 @@ module OAuth2
49
49
  # When using schemes that don't require the client_secret to be passed i.e TLS Client Auth,
50
50
  # we don't want to send the secret
51
51
  def apply_client_id(params)
52
- { 'client_id' => id }.merge(params)
52
+ {'client_id' => id}.merge(params)
53
53
  end
54
54
 
55
55
  # Adds an `Authorization` header with Basic Auth credentials if and only if
data/lib/oauth2/client.rb CHANGED
@@ -4,6 +4,8 @@ require 'logger'
4
4
  module OAuth2
5
5
  # The OAuth2::Client class
6
6
  class Client # rubocop:disable Metrics/ClassLength
7
+ RESERVED_PARAM_KEYS = %w[headers parse].freeze
8
+
7
9
  attr_reader :id, :secret, :site
8
10
  attr_accessor :options
9
11
  attr_writer :connection
@@ -23,8 +25,8 @@ module OAuth2
23
25
  # @option opts [Symbol] :auth_scheme (:basic_auth) HTTP method to use to authorize request (:basic_auth or :request_body)
24
26
  # @option opts [Hash] :connection_opts ({}) Hash of connection options to pass to initialize Faraday with
25
27
  # @option opts [FixNum] :max_redirects (5) maximum number of redirects to follow
26
- # @option opts [Boolean] :raise_errors (true) whether or not to raise an OAuth2::Error
27
- # on responses with 400+ status codes
28
+ # @option opts [Boolean] :raise_errors (true) whether or not to raise an OAuth2::Error on responses with 400+ status codes
29
+ # @option opts [Proc] :extract_access_token proc that extracts the access token from the response
28
30
  # @yield [builder] The Faraday connection builder
29
31
  def initialize(client_id, client_secret, options = {}, &block)
30
32
  opts = options.dup
@@ -32,14 +34,18 @@ module OAuth2
32
34
  @secret = client_secret
33
35
  @site = opts.delete(:site)
34
36
  ssl = opts.delete(:ssl)
35
- @options = {:authorize_url => '/oauth/authorize',
36
- :token_url => '/oauth/token',
37
- :token_method => :post,
38
- :auth_scheme => :request_body,
39
- :connection_opts => {},
40
- :connection_build => block,
41
- :max_redirects => 5,
42
- :raise_errors => true}.merge(opts)
37
+
38
+ @options = {
39
+ :authorize_url => '/oauth/authorize',
40
+ :token_url => '/oauth/token',
41
+ :token_method => :post,
42
+ :auth_scheme => :request_body,
43
+ :connection_opts => {},
44
+ :connection_build => block,
45
+ :max_redirects => 5,
46
+ :raise_errors => true,
47
+ :extract_access_token => DEFAULT_EXTRACT_ACCESS_TOKEN,
48
+ }.merge(opts)
43
49
  @options[:connection_opts][:ssl] = ssl if ssl
44
50
  end
45
51
 
@@ -91,7 +97,7 @@ module OAuth2
91
97
  # code response for this request. Will default to client option
92
98
  # @option opts [Symbol] :parse @see Response::initialize
93
99
  # @yield [req] The Faraday request
94
- def request(verb, url, opts = {}) # rubocop:disable CyclomaticComplexity, MethodLength, Metrics/AbcSize
100
+ def request(verb, url, opts = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
95
101
  connection.response :logger, ::Logger.new($stdout) if ENV['OAUTH_DEBUG'] == 'true'
96
102
 
97
103
  url = connection.build_url(url).to_s
@@ -107,6 +113,7 @@ module OAuth2
107
113
  opts[:redirect_count] ||= 0
108
114
  opts[:redirect_count] += 1
109
115
  return response if opts[:redirect_count] > options[:max_redirects]
116
+
110
117
  if response.status == 303
111
118
  verb = :get
112
119
  opts.delete(:body)
@@ -118,6 +125,7 @@ module OAuth2
118
125
  when 400..599
119
126
  error = Error.new(response)
120
127
  raise(error) if opts.fetch(:raise_errors, options[:raise_errors])
128
+
121
129
  response.error = error
122
130
  response
123
131
  else
@@ -132,7 +140,16 @@ module OAuth2
132
140
  # @param [Hash] access token options, to pass to the AccessToken object
133
141
  # @param [Class] class of access token for easier subclassing OAuth2::AccessToken
134
142
  # @return [AccessToken] the initialized AccessToken
135
- def get_token(params, access_token_opts = {}, access_token_class = AccessToken) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
143
+ def get_token(params, access_token_opts = {}, extract_access_token = options[:extract_access_token]) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
144
+ params = params.map do |key, value|
145
+ if RESERVED_PARAM_KEYS.include?(key)
146
+ [key.to_sym, value]
147
+ else
148
+ [key, value]
149
+ end
150
+ end
151
+ params = Hash[params]
152
+
136
153
  params = Authenticator.new(id, secret, options[:auth_scheme]).apply(params)
137
154
  opts = {:raise_errors => options[:raise_errors], :parse => params.delete(:parse)}
138
155
  headers = params.delete(:headers) || {}
@@ -145,11 +162,18 @@ module OAuth2
145
162
  end
146
163
  opts[:headers].merge!(headers)
147
164
  response = request(options[:token_method], token_url, opts)
148
- if options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token'])
165
+
166
+ access_token = begin
167
+ build_access_token(response, access_token_opts, extract_access_token)
168
+ rescue StandardError
169
+ nil
170
+ end
171
+
172
+ if options[:raise_errors] && !access_token
149
173
  error = Error.new(response)
150
174
  raise(error)
151
175
  end
152
- access_token_class.from_hash(self, response.parsed.merge(access_token_opts))
176
+ access_token
153
177
  end
154
178
 
155
179
  # The Authorization Code strategy
@@ -207,5 +231,27 @@ module OAuth2
207
231
  {}
208
232
  end
209
233
  end
234
+
235
+ DEFAULT_EXTRACT_ACCESS_TOKEN = proc do |client, hash|
236
+ token = hash.delete('access_token') || hash.delete(:access_token)
237
+ token && AccessToken.new(client, token, hash)
238
+ end
239
+
240
+ private
241
+
242
+ def build_access_token(response, access_token_opts, extract_access_token)
243
+ parsed_response = response.parsed.dup
244
+ return unless parsed_response.is_a?(Hash)
245
+
246
+ hash = parsed_response.merge(access_token_opts)
247
+
248
+ # Provide backwards compatibility for old AcessToken.form_hash pattern
249
+ # Should be deprecated in 2.x
250
+ if extract_access_token.is_a?(Class) && extract_access_token.respond_to?(:from_hash)
251
+ extract_access_token.from_hash(self, hash)
252
+ else
253
+ extract_access_token.call(self, hash)
254
+ end
255
+ end
210
256
  end
211
257
  end