# 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})
+
+
+
Parameters:
@@ -967,7 +979,7 @@
:mode
- (Symbol or callable)
+ (Symbol, Hash, or callable)
— default:
@@ -976,7 +988,8 @@
—
the transmission mode of the Access Token parameter value:
-either one of :header, :body or :query, or a callable that accepts a request-verb parameter
+either one of :header, :body or :query; or a Hash with verb symbols as keys mapping to one of these symbols
+(e.g., :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 215defrefresh(params={},access_token_opts={},&block)raiseOAuth2::Error.new({error:"A refresh_token is not available"})unlessrefresh_token
@@ -2698,13 +2711,13 @@
-327
-328
-329
-330
+332
+333
+334
+335
-
# File 'lib/oauth2/access_token.rb', line 327
+
# File 'lib/oauth2/access_token.rb', line 332defrequest(verb,path,opts={},&block)configure_authentication!(opts,verb)
@@ -2912,11 +2925,6 @@
diff --git a/docs/file.CHANGELOG.html b/docs/file.CHANGELOG.html
index ba516ac9..1efddcb6 100644
--- a/docs/file.CHANGELOG.html
+++ b/docs/file.CHANGELOG.html
@@ -68,26 +68,30 @@
and yes, platform and engine support are part of the public API.
Please file a bug if you notice a violation of semantic versioning.
-
Another Way to Support Open
diff --git a/docs/file.LICENSE.html b/docs/file.LICENSE.html
index 752c9ba5..f2be648d 100644
--- a/docs/file.LICENSE.html
+++ b/docs/file.LICENSE.html
@@ -60,7 +60,7 @@
MIT License
Copyright (c) 2017-2025 Peter H. Boling, of Galtzo.com, and oauth2 contributors Copyright (c) 2011-2013 Michael Bleigh and Intridea, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/gemfiles/modular/injected.gemfile b/gemfiles/modular/injected.gemfile
index 0b5f8fa7..175b724a 100644
--- a/gemfiles/modular/injected.gemfile
+++ b/gemfiles/modular/injected.gemfile
@@ -2,7 +2,7 @@
# visibility and discoverability on RubyGems.org.
# However, this gem sits underneath all my other gems, and also "depends on" many of them.
# So instead of depending on them directly it injects them into the other gem's gemspec on install.
-# This gem its injected dev dependencies, will install on Ruby down to 2.3.x.
+# This gem, and its injected dev dependencies, will install on Ruby down to 2.3.x.
# This gem does not inject runtime dependencies.
# Thus, dev dependencies injected into gemspecs must have
#
diff --git a/lib/oauth2/access_token.rb b/lib/oauth2/access_token.rb
index e598d110..c428c019 100644
--- a/lib/oauth2/access_token.rb
+++ b/lib/oauth2/access_token.rb
@@ -132,10 +132,15 @@ def no_tokens_warning(hash, key)
# @option opts [FixNum, String] :expires_in (nil) the number of seconds in which the AccessToken will expire
# @option opts [FixNum, String] :expires_at (nil) the epoch time in seconds in which AccessToken will expire
# @option opts [FixNum, String] :expires_latency (nil) the number of seconds by which AccessToken validity will be reduced to offset latency, @version 2.0+
- # @option opts [Symbol or callable] :mode (:header) the transmission mode of the Access Token parameter value:
- # either one of :header, :body or :query, or a callable that accepts a request-verb parameter
+ # @option opts [Symbol, Hash, or callable] :mode (:header) 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.
# @option opts [String] :header_format ('Bearer %s') the string format to use for the Authorization header
+ #
+ # @example 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})
# @option opts [String] :param_name ('access_token') the parameter name to use for transmission of the
# Access Token value in :body or :query transmission mode
# @option opts [String] :token_name (nil) the name of the response parameter that identifies the access token
@@ -372,7 +377,18 @@ def headers
private
def configure_authentication!(opts, verb)
- mode = options[:mode].respond_to?(:call) ? options[:mode].call(verb) : options[:mode]
+ mode_opt = options[:mode]
+ mode =
+ if mode_opt.respond_to?(:call)
+ mode_opt.call(verb)
+ elsif mode_opt.is_a?(Hash)
+ key = verb.to_sym
+ # Try symbol key first, then string key; default to :header when missing
+ mode_opt[key] || mode_opt[key.to_s] || :header
+ else
+ mode_opt
+ end
+
case mode
when :header
opts[:headers] ||= {}
diff --git a/oauth2.gemspec b/oauth2.gemspec
index b3358902..471e279a 100644
--- a/oauth2.gemspec
+++ b/oauth2.gemspec
@@ -153,7 +153,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", ">= 1.1.9") # ruby >= 2.3
+ spec.add_development_dependency("kettle-dev", "~> 1.1", ">= 1.1.20") # ruby >= 2.3.0
# Security
spec.add_development_dependency("bundler-audit", "~> 0.9.2") # ruby >= 2.0.0
diff --git a/sig/oauth2/access_token.rbs b/sig/oauth2/access_token.rbs
index f2e414e9..06779891 100644
--- a/sig/oauth2/access_token.rbs
+++ b/sig/oauth2/access_token.rbs
@@ -17,7 +17,7 @@ module OAuth2
def patch: (String, ?Hash[Symbol, untyped]) { (untyped) -> void } -> OAuth2::Response
def delete: (String, ?Hash[Symbol, untyped]) { (untyped) -> void } -> OAuth2::Response
def headers: () -> Hash[String, String]
- def configure_authentication!: (Hash[Symbol, untyped]) -> void
+ def configure_authentication!: (Hash[Symbol, untyped], Symbol) -> void
def convert_expires_at: (untyped) -> (Time | Integer | nil)
attr_accessor response: OAuth2::Response
diff --git a/spec/oauth2/access_token_spec.rb b/spec/oauth2/access_token_spec.rb
index 2234b2cd..97f9a706 100644
--- a/spec/oauth2/access_token_spec.rb
+++ b/spec/oauth2/access_token_spec.rb
@@ -446,6 +446,36 @@ def assert_initialized_token(target)
end
end
+ context "with verb-dependent Hash mode" do
+ let(:mode_hash) do
+ {get: :query, post: :header, delete: :header, put: :body, patch: :body}
+ end
+ let(:options) { {mode: mode_hash} }
+
+ VERBS.each do |verb|
+ it "correctly handles a #{verb.to_s.upcase} via Hash" do
+ expected = mode_hash[verb] || :header
+ expect(subject.__send__(verb, "/token/#{expected}").body).to include(token)
+ end
+ end
+
+ context "with fallback to :header for missing key" do
+ let(:mode_hash) { {get: :query} }
+
+ it "defaults POST to header when not specified" do
+ expect(subject.post("/token/header").body).to include(token)
+ end
+ end
+
+ context "when invalid value" do
+ let(:mode_hash) { {get: "foobar"} }
+
+ it "raises an error for invalid mapping" do
+ expect { subject.get("/token/foobar") }.to raise_error("invalid :mode option of foobar")
+ end
+ end
+ end
+
context "with client.options[:raise_errors] = false" do
let(:options) { {raise_errors: false} }