For “soon-to-expire”/”clock-skew” functionality see the :expires_latency option.
-
-
-
-
- Note:
-
If no token is provided, the AccessToken will be considered invalid.
-This is to prevent the possibility of a token being accidentally
-created with no token value.
-If you want to create an AccessToken with no token value,
-you can pass in an empty string or nil for the token value.
-If you want to create an AccessToken with no token value and
-no refresh token, you can pass in an empty string or nil for the
-token value and nil for the refresh token, and raise_errors: false.
-
-
-
-
Initialize an AccessToken
-
-
-
-
-
-
-
-
Examples:
-
-
-
Verb-dependent Hash mode
-
-
-
# Send token in query for GET, in header for POST/DELETE, in body for PUT/PATCH
-OAuth2::AccessToken.new(client,token,mode:{get::query,post::header,delete::header,put::body,patch::body})
the transmission mode of the Access Token parameter value:
-either one of :header, :body or :query; or a Hash with verb symbols as keys mapping to one of these symbols
-(e.g., {get: :query, post: :header, delete: :header}); or a callable that accepts a request-verb parameter
-and returns one of these three symbols.
# File 'lib/oauth2/access_token.rb', line 57
-
-deffrom_hash(client,hash)
- fresh=hash.dup
- # If token_name is present, then use that key name
-key=
- iffresh.key?(:token_name)
- t_key=fresh[:token_name]
- no_tokens_warning(fresh,t_key)
- t_key
- else
- # Otherwise, if one of the supported default keys is present, use whichever has precedence
-supported_keys=TOKEN_KEY_LOOKUP&fresh.keys
- t_key=supported_keys[0]
- extra_tokens_warning(supported_keys,t_key)
- t_key
- end
- # :nocov:
-# TODO: Get rid of this branching logic when dropping Hashie < v3.2
-token=if!defined?(Hashie::VERSION)# i.e. <= "1.1.0"; the first Hashie to ship with a VERSION constant
-warn("snaky_hash and oauth2 will drop support for Hashie v0 in the next major version. Please upgrade to a modern Hashie.")
- # There is a bug in Hashie v0, which is accounts for.
-fresh.delete(key)||fresh[key]||""
- else
- fresh.delete(key)||""
- end
- # :nocov:
-new(client,token,fresh)
-end
# File 'lib/oauth2/access_token.rb', line 215
-
-defrefresh(params={},access_token_opts={},&block)
- raiseOAuth2::Error.new({error:"A refresh_token is not available"})unlessrefresh_token
-
- params[:grant_type]="refresh_token"
- params[:refresh_token]=refresh_token
- new_token=@client.get_token(params,access_token_opts,&block)
- new_token.options=options
- ifnew_token.refresh_token
- # Keep it if there is one
-else
- new_token.refresh_token=refresh_token
- end
- new_token
-end
If the token passed to the request
-is an access token, the server MAY revoke the respective refresh
-token as well.
-
-
-
-
- Note:
-
If the token passed to the request
-is a refresh token and the authorization server supports the
-revocation of access tokens, then the authorization server SHOULD
-also invalidate all access tokens based on the same authorization
-grant
-
-
-
-
- Note:
-
If the server responds with HTTP status code 503, your code must
-assume the token still exists and may retry after a reasonable delay.
-The server may include a “Retry-After” header in the response to
-indicate how long the service is expected to be unavailable to the
-requesting client.
# File 'lib/oauth2/access_token.rb', line 264
-
-defrevoke(params={},&block)
- token_type_hint_orig=params.delete(:token_type_hint)
- token_type_hint=nil
- revoke_token=casetoken_type_hint_orig
- when"access_token",:access_token
- token_type_hint="access_token"
- token
- when"refresh_token",:refresh_token
- token_type_hint="refresh_token"
- refresh_token
- whennil
- iftoken
- token_type_hint="access_token"
- token
- elsifrefresh_token
- token_type_hint="refresh_token"
- refresh_token
- end
- else
- raiseOAuth2::Error.new({error:"token_type_hint must be one of [nil, :refresh_token, :access_token], so if you need something else consider using a subclass or entirely custom AccessToken class."})
- end
- raiseOAuth2::Error.new({error:"#{token_type_hint||"unknown token type"} is not available for revoking"})unlessrevoke_token&&!revoke_token.empty?
-
- @client.revoke_token(revoke_token,token_type_hint,params,&block)
-end
-
-
-
-
-
-
-
-
- #to_hash ⇒ Hash
-
-
-
-
-
-
-
-
-
- Note:
-
Don’t return expires_latency because it has already been deducted from expires_at
-
-
-
-
Convert AccessToken to a hash which can be used to rebuild itself with AccessToken.from_hash
This Incident Response Plan (IRP) defines the steps the project maintainer(s) will follow when handling security incidents related to the oauth2 gem. It is written for a small project with a single primary maintainer and is intended to be practical, concise, and actionable.
-
-
Scope
-
-
Applies to security incidents that affect the oauth2 codebase, releases (gems), CI/CD infrastructure related to building and publishing the gem, repository credentials, or any compromise of project infrastructure that could impact users.
-
-
Key assumptions
-
-
This project is maintained primarily by a single maintainer.
-
Public vulnerability disclosure is handled via Tidelift (see SECURITY.md).
-
The maintainer will act as incident commander unless otherwise delegated.
-
-
-
Contact & Roles
-
-
-
Incident Commander: Primary maintainer (repo owner). Responsible for coordinating triage, remediation, and communications.
-
Secondary Contact: (optional) A trusted collaborator or organization contact if available.
-
-
-
If you are an external reporter
-
-
Do not publicly disclose details of an active vulnerability before coordination via Tidelift.
-
See SECURITY.md for Tidelift disclosure instructions. If the reporter has questions and cannot use Tidelift, they may open a direct encrypted report as described in SECURITY.md (if available) or email the maintainer contact listed in the repository.
-
-
-
Incident Handling Workflow (high level)
-
-
Identification & Reporting
-
-
Reports may arrive via Tidelift, issue tracker, direct email, or third-party advisories.
-
Immediately acknowledge receipt (within 24-72 hours) via the reporting channel.
-
-
-
Triage & Initial Assessment (first 72 hours)
-
-
Confirm the report is not duplicative and gather: reproducer, affected versions, attack surface, exploitability, and CVSS-like severity estimate.
-
Verify the issue against the codebase and reproduce locally if possible.
-
Determine scope: which versions are affected, whether the issue is in code paths executed in common setups, and whether a workaround exists.
-
-
-
Containment & Mitigation
-
-
If a simple mitigation or workaround (configuration change, safe default, or recommended upgrade) exists, document it clearly in the issue/Tidelift advisory.
-
If immediate removal of a release is required (rare), consult Tidelift for coordinated takedown and notify package hosts if applicable.
-
-
-
Remediation & Patch
-
-
Prepare a fix in a branch with tests and changelog entries. Prefer minimal, well-tested changes.
-
Include tests that reproduce the faulty behavior and demonstrate the fix.
-
Hardening: add fuzz tests, input validation, or additional checks as appropriate.
-
-
-
Release & Disclosure
-
-
Coordinate disclosure through Tidelift per SECURITY.md timelines. Aim for a coordinated disclosure and patch release to minimize risk to users.
-
Publish a patch release (increment gem version) and an advisory via Tidelift.
-
Update CHANGELOG.md and repository release notes with non-sensitive details.
-
-
-
Post-Incident
-
-
Produce a short postmortem: timeline, root cause, actions taken, and follow-ups.
-
Add/adjust tests and CI checks to prevent regressions.
-
If credentials or infrastructure were compromised, rotate secrets and audit access.
-
-
-
-
-
Severity classification (guidance)
-
-
High/Critical: Remote code execution, data exfiltration, or any vulnerability that can be exploited without user interaction. Immediate action and prioritized patching.
-
Medium: Privilege escalation, sensitive information leaks that require specific conditions. Patch in the next release cycle with advisory.
-
Low: Minor information leaks, UI issues, or non-exploitable bugs. Fix normally and include in the next scheduled release.
-
-
-
Preservation of evidence
-
-
Preserve all reporter-provided data, logs, and reproducer code in a secure location (local encrypted storage or private branch) for the investigation.
-
Do not publish evidence that would enable exploitation before coordinated disclosure.
-
-
-
Communication templates
-
Acknowledgement (to reporter)
-
-
“Thank you for reporting this issue. I’ve received your report and will triage it within 72 hours. If you can, please provide reproduction steps, affected versions, and any exploit PoC. I will coordinate disclosure through Tidelift per the project’s security policy.”
-
-
Public advisory (after patch is ready)
-
-
“A security advisory for oauth2 (versions X.Y.Z) has been published via Tidelift. Please upgrade to version A.B.C which patches [brief description]. See the advisory for details and recommended mitigations.”
-
-
Runbook: Quick steps for a maintainer to patch and release
-
-
Create a branch: git checkout -b fix/security-brief-description
-
-
Reproduce the issue locally and add a regression spec in spec/.
-
Implement the fix and run the test suite: bundle exec rspec (or the project’s preferred test command).
-
Bump version in lib/oauth2/version.rb following semantic versioning.
-
Update CHANGELOG.md with an entry describing the fix (avoid exploit details).
-
Commit and push the branch, open a PR, and merge after approvals.
-
Build and push the gem: gem build oauth2.gemspec && gem push pkg/... (coordinate with Tidelift before public push if disclosure is coordinated).
-
Publish a release on GitHub and ensure the Tidelift advisory is posted.
-
-
-
Operational notes
-
-
Secrets: Use local encrypted storage for any sensitive reporter data. If repository or CI secrets may be compromised, rotate them immediately and update dependent services.
-
Access control: Limit who can publish gems and who has admin access to the repo. Keep an up-to-date list of collaborators in a secure place.
-
-
-
Legal & regulatory
-
-
If the incident involves user data or has legal implications, consult legal counsel or the maintainers’ employer as appropriate. The maintainer should document the timeline and all communications.
-
-
-
Retrospective & continuous improvement
-
After an incident, perform a brief post-incident review covering:
-
-
What happened and why
-
What was done to contain and remediate
-
What tests or process changes will prevent recurrence
-
Assign owners and deadlines for follow-up tasks
-
-
-
References
-
-
See SECURITY.md for the project’s official disclosure channel (Tidelift).
-
-
-
Appendix: Example checklist for an incident
-
-
-Acknowledge report to reporter (24-72 hours)
-
-Reproduce and classify severity
-
-Prepare and test a fix in a branch
-
-Coordinate disclosure via Tidelift
-
-Publish patch release and advisory
-
-Postmortem and follow-up actions
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/file.oauth2-2.0.13.gem.html b/docs/file.oauth2-2.0.13.gem.html
index 8068efe3..e69de29b 100644
--- a/docs/file.oauth2-2.0.13.gem.html
+++ b/docs/file.oauth2-2.0.13.gem.html
@@ -1,71 +0,0 @@
-
-
-
-
-
-
- File: oauth2-2.0.13.gem
-
- — Documentation by YARD 0.9.37
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gemfiles/modular/runtime_heads.gemfile b/gemfiles/modular/runtime_heads.gemfile
index 7d74c143..787adeab 100644
--- a/gemfiles/modular/runtime_heads.gemfile
+++ b/gemfiles/modular/runtime_heads.gemfile
@@ -15,7 +15,7 @@ gem "jwt", github: "jwt/ruby-jwt", branch: "main"
gem "logger", github: "ruby/logger", branch: "master"
# Ruby >= 3.2
-gem "multi_xml", github: "sferik/multi_xml", branch: "master"
+gem "multi_xml", github: "sferik/multi_xml", branch: "main"
# Ruby >= 2.4
gem "rack", github: "rack/rack", branch: "main"
diff --git a/lib/oauth2.rb b/lib/oauth2.rb
index f0fd7f8b..46a11a97 100644
--- a/lib/oauth2.rb
+++ b/lib/oauth2.rb
@@ -52,27 +52,21 @@ module OAuth2
# The current runtime configuration for the library.
#
# @return [SnakyHash::SymbolKeyed]
- @config = DEFAULT_CONFIG.dup
-
class << self
- # Access the current configuration.
+ def config
+ @config ||= DEFAULT_CONFIG.dup
+ end
+
+ # Configure global library behavior.
#
- # Prefer using {OAuth2.configure} to mutate configuration.
+ # Yields the mutable configuration object so callers can update settings.
#
- # @return [SnakyHash::SymbolKeyed]
- attr_reader :config
- end
-
- # Configure global library behavior.
- #
- # Yields the mutable configuration object so callers can update settings.
- #
- # @yieldparam [SnakyHash::SymbolKeyed] config the configuration object
- # @return [void]
- def configure
- yield @config
+ # @yieldparam [SnakyHash::SymbolKeyed] config the configuration object
+ # @return [void]
+ def configure
+ yield config
+ end
end
- module_function :configure
end
# Extend OAuth2::Version with VersionGem helpers to provide semantic version helpers.
diff --git a/lib/oauth2/access_token.rb b/lib/oauth2/access_token.rb
index 8c68e321..6f028945 100644
--- a/lib/oauth2/access_token.rb
+++ b/lib/oauth2/access_token.rb
@@ -57,26 +57,23 @@ class << self
def from_hash(client, hash)
fresh = hash.dup
# If token_name is present, then use that key name
- key =
- if fresh.key?(:token_name)
- t_key = fresh[:token_name]
- no_tokens_warning(fresh, t_key)
- t_key
- else
- # Otherwise, if one of the supported default keys is present, use whichever has precedence
- supported_keys = TOKEN_KEY_LOOKUP & fresh.keys
- t_key = supported_keys[0]
- extra_tokens_warning(supported_keys, t_key)
- t_key
- end
+ if fresh.key?(:token_name)
+ t_key = fresh[:token_name]
+ no_tokens_warning(fresh, t_key)
+ else
+ # Otherwise, if one of the supported default keys is present, use whichever has precedence
+ supported_keys = TOKEN_KEY_LOOKUP & fresh.keys
+ t_key = supported_keys[0]
+ extra_tokens_warning(supported_keys, t_key)
+ end
# :nocov:
# TODO: Get rid of this branching logic when dropping Hashie < v3.2
token = if !defined?(Hashie::VERSION) # i.e. <= "1.1.0"; the first Hashie to ship with a VERSION constant
warn("snaky_hash and oauth2 will drop support for Hashie v0 in the next major version. Please upgrade to a modern Hashie.")
# There is a bug in Hashie v0, which is accounts for.
- fresh.delete(key) || fresh[key] || ""
+ fresh.delete(t_key) || fresh[t_key] || ""
else
- fresh.delete(key) || ""
+ fresh.delete(t_key) || ""
end
# :nocov:
new(client, token, fresh)
diff --git a/lib/oauth2/authenticator.rb b/lib/oauth2/authenticator.rb
index 5fbdc758..f9a8b5a5 100644
--- a/lib/oauth2/authenticator.rb
+++ b/lib/oauth2/authenticator.rb
@@ -51,13 +51,15 @@ def apply(params)
end
end
- # Encodes a Basic Authorization header value for the provided credentials.
- #
- # @param [String] user The client identifier
- # @param [String] password The client secret
- # @return [String] The value to use for the Authorization header
- def self.encode_basic_auth(user, password)
- "Basic #{Base64.strict_encode64("#{user}:#{password}")}"
+ class << self
+ # Encodes a Basic Authorization header value for the provided credentials.
+ #
+ # @param [String] user The client identifier
+ # @param [String] password The client secret
+ # @return [String] The value to use for the Authorization header
+ def encode_basic_auth(user, password)
+ "Basic #{Base64.strict_encode64("#{user}:#{password}")}"
+ end
end
private
diff --git a/lib/oauth2/filtered_attributes.rb b/lib/oauth2/filtered_attributes.rb
index c1da8247..71204621 100644
--- a/lib/oauth2/filtered_attributes.rb
+++ b/lib/oauth2/filtered_attributes.rb
@@ -16,19 +16,37 @@ def self.included(base)
# Class-level helpers for configuring filtered attributes.
module ClassMethods
+ class << self
+ # Declare attributes that should be redacted in inspect output.
+ #
+ # @param [Array] attributes One or more attribute names
+ # @return [void]
+ def filtered_attributes(base, *attributes)
+ base.instance_variable_set(:@filtered_attribute_names, attributes.map(&:to_sym))
+ end
+
+ # The configured attribute names to filter.
+ #
+ # @param [Class] base The class to get filtered attributes for
+ # @return [Array]
+ def filtered_attribute_names(base)
+ base.instance_variable_get(:@filtered_attribute_names) || []
+ end
+ end
+
# Declare attributes that should be redacted in inspect output.
#
# @param [Array] attributes One or more attribute names
# @return [void]
def filtered_attributes(*attributes)
- @filtered_attribute_names = attributes.map(&:to_sym)
+ ClassMethods.filtered_attributes(self, *attributes)
end
# The configured attribute names to filter.
#
# @return [Array]
def filtered_attribute_names
- @filtered_attribute_names || []
+ ClassMethods.filtered_attribute_names(self)
end
end
@@ -36,7 +54,7 @@ def filtered_attribute_names
#
# @return [String]
def inspect
- filtered_attribute_names = self.class.filtered_attribute_names
+ filtered_attribute_names = ClassMethods.filtered_attribute_names(self.class)
return super if filtered_attribute_names.empty?
inspected_vars = instance_variables.map do |var|
diff --git a/lib/oauth2/response.rb b/lib/oauth2/response.rb
index fb47c381..1c2e7c11 100644
--- a/lib/oauth2/response.rb
+++ b/lib/oauth2/response.rb
@@ -43,18 +43,20 @@ class Response
"text/plain" => :text,
}
- # Adds a new content type parser.
- #
- # @param [Symbol] key A descriptive symbol key such as :json or :query
- # @param [Array, String] mime_types One or more mime types to which this parser applies
- # @yield [String] Block that will be called to parse the response body
- # @yieldparam [String] body The response body to parse
- # @return [void]
- def self.register_parser(key, mime_types, &block)
- key = key.to_sym
- @@parsers[key] = block
- Array(mime_types).each do |mime_type|
- @@content_types[mime_type] = key
+ class << self
+ # Adds a new content type parser.
+ #
+ # @param [Symbol] key A descriptive symbol key such as :json or :query
+ # @param [Array, String] mime_types One or more mime types to which this parser applies
+ # @yield [String] Block that will be called to parse the response body
+ # @yieldparam [String] body The response body to parse
+ # @return [void]
+ def register_parser(key, mime_types, &block)
+ key = key.to_sym
+ @@parsers[key] = block
+ Array(mime_types).each do |mime_type|
+ @@content_types[mime_type] = key
+ end
end
end
diff --git a/oauth2.gemspec b/oauth2.gemspec
index a1d34e52..8d15211c 100644
--- a/oauth2.gemspec
+++ b/oauth2.gemspec
@@ -152,7 +152,7 @@ Thanks, @pboling / @galtzo
spec.add_development_dependency("rexml", "~> 3.2", ">= 3.2.5") # ruby >= 0
# Dev, Test, & Release Tasks
- spec.add_development_dependency("kettle-dev", "~> 1.1") # ruby >= 2.3.0
+ spec.add_development_dependency("kettle-dev", "~> 2.0") # ruby >= 2.3.0
# Security
spec.add_development_dependency("bundler-audit", "~> 0.9.2") # ruby >= 2.0.0
@@ -164,12 +164,12 @@ Thanks, @pboling / @galtzo
spec.add_development_dependency("require_bench", "~> 1.0", ">= 1.0.4") # ruby >= 2.2.0
# Testing
- spec.add_development_dependency("appraisal2", "~> 3.0") # ruby >= 1.8.7, for testing against multiple versions of dependencies
- spec.add_development_dependency("kettle-test", "~> 1.0", ">= 1.0.6") # ruby >= 2.3
+ spec.add_development_dependency("appraisal2", "~> 3.0", ">= 3.0.6") # ruby >= 1.8.7, for testing against multiple versions of dependencies
+ spec.add_development_dependency("kettle-test", "~> 1.0", ">= 1.0.10") # ruby >= 2.3
# Releasing
spec.add_development_dependency("ruby-progressbar", "~> 1.13") # ruby >= 0
- spec.add_development_dependency("stone_checksums", "~> 1.0", ">= 1.0.2") # ruby >= 2.2.0
+ spec.add_development_dependency("stone_checksums", "~> 1.0", ">= 1.0.3") # ruby >= 2.2.0
# Git integration (optional)
# The 'git' gem is optional; oauth2 falls back to shelling out to `git` if it is not present.
diff --git a/spec/oauth2/access_token_spec.rb b/spec/oauth2/access_token_spec.rb
index 97f9a706..c59f1607 100644
--- a/spec/oauth2/access_token_spec.rb
+++ b/spec/oauth2/access_token_spec.rb
@@ -851,7 +851,7 @@ def assert_initialized_token(target)
end
end
- context "params include [number]" do
+ context "with params including [number]" do
VERBS.each do |verb|
it "sends #{verb.to_s.upcase} correct query" do
expect(subject.__send__(verb, "/token/query_string", params: {"foo[bar][1]" => "val"}).body).to include("foo[bar][1]=val")
@@ -921,12 +921,14 @@ def assert_initialized_token(target)
before do
custom_class = Class.new(described_class) do
- def self.from_hash(client, hash)
- new(client, hash.delete("access_token"), hash)
- end
+ class << self
+ def from_hash(client, hash)
+ new(client, hash.delete("access_token"), hash)
+ end
- def self.contains_token?(hash)
- hash.key?("refresh_token")
+ def contains_token?(hash)
+ hash.key?("refresh_token")
+ end
end
end
diff --git a/spec/oauth2/authenticator_spec.rb b/spec/oauth2/authenticator_spec.rb
index f7396c5e..e39a28c5 100644
--- a/spec/oauth2/authenticator_spec.rb
+++ b/spec/oauth2/authenticator_spec.rb
@@ -48,7 +48,7 @@
)
end
- context "passing nil secret" do
+ context "with nil secret" do
let(:client_secret) { nil }
it "does not set nil client_secret" do
@@ -57,7 +57,7 @@
end
end
- context "using tls client authentication" do
+ context "with tls client authentication" do
let(:mode) { :tls_client_auth }
it "does not add client_secret" do
@@ -66,7 +66,7 @@
end
end
- context "using private key jwt authentication" do
+ context "with private key jwt authentication" do
let(:mode) { :private_key_jwt }
it "does not include client_id or client_secret" do
@@ -76,7 +76,7 @@
end
end
- context "using tls_client_auth" do
+ context "with tls_client_auth" do
let(:mode) { :tls_client_auth }
context "when client_id present" do
diff --git a/spec/oauth2/client_spec.rb b/spec/oauth2/client_spec.rb
index 741e7568..45d786ec 100644
--- a/spec/oauth2/client_spec.rb
+++ b/spec/oauth2/client_spec.rb
@@ -180,7 +180,7 @@
end
end
end
- client.auth_code.get_token("code")
+ expect(client.auth_code.get_token("code")).to be_a(OAuth2::AccessToken)
end
end
@@ -199,7 +199,7 @@
end
end
end
- client.auth_code.get_token("code")
+ expect(client.auth_code.get_token("code")).to be_a(OAuth2::AccessToken)
end
end
@@ -842,7 +842,7 @@
[200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
- client.get_token({})
+ expect(client.get_token({})).to be_a(OAuth2::AccessToken)
end
it "authenticates with Basic auth" do
@@ -853,7 +853,7 @@
[200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
- client.get_token({})
+ expect(client.get_token({})).to be_a(OAuth2::AccessToken)
end
it "authenticates with JSON" do
@@ -862,7 +862,7 @@
[200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
- client.get_token(headers: {"Content-Type" => "application/json"})
+ expect(client.get_token(headers: {"Content-Type" => "application/json"})).to be_a(OAuth2::AccessToken)
end
it "sets the response object on the access token" do
@@ -984,12 +984,14 @@
custom_class = Class.new(OAuth2::AccessToken) do
attr_accessor :response
- def self.from_hash(client, hash)
- new(client, hash.delete("custom_token"))
- end
+ class << self
+ def from_hash(client, hash)
+ new(client, hash.delete("custom_token"))
+ end
- def self.contains_token?(hash)
- hash.key?("custom_token")
+ def contains_token?(hash)
+ hash.key?("custom_token")
+ end
end
end
@@ -997,7 +999,7 @@ def self.contains_token?(hash)
end
it "returns the parsed :custom_token from body" do
- client.get_token({})
+ expect(client.get_token({})).to be_a(CustomAccessToken)
end
context "when the :raise_errors flag is set to true" do
@@ -1084,12 +1086,14 @@ def self.contains_token?(hash)
def initialize(client, hash)
end
- def self.from_hash(client, hash)
- new(client, hash.delete("custom_token"))
- end
+ class << self
+ def from_hash(client, hash)
+ new(client, hash.delete("custom_token"))
+ end
- def self.contains_token?(hash)
- hash.key?("custom_token")
+ def contains_token?(hash)
+ hash.key?("custom_token")
+ end
end
end
diff --git a/spec/oauth2/response_spec.rb b/spec/oauth2/response_spec.rb
index 2a1c42be..e0d37eb9 100644
--- a/spec/oauth2/response_spec.rb
+++ b/spec/oauth2/response_spec.rb
@@ -388,7 +388,7 @@
# Give this hash class `dump` and `load` abilities!
extend SnakyHash::Serializer
- unless instance_methods.include?(:transform_keys)
+ unless method_defined?(:transform_keys)
# Patch our custom Hash to support Ruby < 2.4.2
def transform_keys!
keys.each do |key|
@@ -539,7 +539,7 @@ def transform_keys
# Give this hash class `dump` and `load` abilities!
extend SnakyHash::Serializer
- unless instance_methods.include?(:transform_keys)
+ unless method_defined?(:transform_keys)
# Patch our custom Hash to support Ruby < 2.4.2
def transform_keys!
keys.each do |key|