Date: Thu, 6 Nov 2025 21:02:34 -0700
Subject: [PATCH 02/14] =?UTF-8?q?=F0=9F=90=9B=20Fixing=20markdown=20=3D>?=
=?UTF-8?q?=20HTML=20conversion?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.tool-versions | 2 +-
.yard_gfm_support.rb | 20 ++++++++++++++++----
docs/.nojekyll | 0
docs/CNAME | 1 -
test_gfm.rb | 32 ++++++++++++++++++++++++++++++++
5 files changed, 49 insertions(+), 6 deletions(-)
delete mode 100644 docs/.nojekyll
delete mode 100644 docs/CNAME
create mode 100644 test_gfm.rb
diff --git a/.tool-versions b/.tool-versions
index d1de26c4..048c75ee 100755
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,2 +1,2 @@
direnv 2.32.2
-ruby 3.4.5
+ruby 3.4.7
diff --git a/.yard_gfm_support.rb b/.yard_gfm_support.rb
index 4f2f1403..3c8a6b0e 100644
--- a/.yard_gfm_support.rb
+++ b/.yard_gfm_support.rb
@@ -11,12 +11,24 @@ def initialize(source, options = {})
end
end
+# Ensure YARD is loaded before modifying its constants
+require 'yard' unless defined?(YARD)
+
# Insert the new provider as the highest priority option for Markdown.
# See:
# - https://github.com/lsegal/yard/issues/1157
# - https://github.com/lsegal/yard/issues/1017
# - https://github.com/lsegal/yard/blob/main/lib/yard/templates/helpers/markup_helper.rb
-YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown].insert(
- 0,
- {const: "KramdownGfmDocument"},
-)
+require 'yard/templates/helpers/markup_helper'
+
+providers = YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown]
+providers.unshift({lib: :kramdown, const: :KramdownGfmDocument})
+
+# Normalize provider entries to what YARD expects (const must be a String)
+providers.each do |provider|
+ const = provider[:const]
+ provider[:const] = const.to_s if const.is_a?(Symbol)
+end
+
+# De-duplicate entries by [lib, const]
+providers.uniq! { |p| [p[:lib], p[:const].to_s] }
diff --git a/docs/.nojekyll b/docs/.nojekyll
deleted file mode 100644
index e69de29b..00000000
diff --git a/docs/CNAME b/docs/CNAME
deleted file mode 100644
index 9e32e7bf..00000000
--- a/docs/CNAME
+++ /dev/null
@@ -1 +0,0 @@
-oauth2.galtzo.com
\ No newline at end of file
diff --git a/test_gfm.rb b/test_gfm.rb
new file mode 100644
index 00000000..75c1dc67
--- /dev/null
+++ b/test_gfm.rb
@@ -0,0 +1,32 @@
+#!/usr/bin/env ruby
+require 'bundler/setup'
+require 'yard'
+require 'yard/templates/helpers/markup_helper'
+
+puts "Before loading .yard_gfm_support.rb:"
+YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown].each_with_index do |p, i|
+ puts " [#{i}] #{p.inspect}"
+end
+
+require './.yard_gfm_support.rb'
+
+puts "\nAfter loading .yard_gfm_support.rb:"
+YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown].each_with_index do |p, i|
+ puts " [#{i}] #{p.inspect}"
+end
+
+puts "\nTesting KramdownGfmDocument:"
+
+test_md = <<-MD
+ # Test
+
+ ```ruby
+ puts "hello"
+ ```
+MD
+
+doc = KramdownGfmDocument.new(test_md)
+html = doc.to_html
+puts html
+puts "\nDoes output contain ? #{html.include?('')}"
+puts "Does output contain ? #{html.include?('
Date: Fri, 7 Nov 2025 16:59:58 -0700
Subject: [PATCH 03/14] =?UTF-8?q?=F0=9F=93=9D=20Code=20fences?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CHANGELOG.md | 2 +-
README.md | 14 +++++++-------
lib/oauth2/access_token.rb | 2 +-
lib/oauth2/strategy/assertion.rb | 4 ++--
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 044437fe..607363f7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -49,7 +49,7 @@ Please file a bug if you notice a violation of semantic versioning.
### Added
-- [gh!682][gh!682] - AccessToken: support Hash-based verb-dependent token transmission mode (e.g., {get: :query, post: :header})
+- [gh!682][gh!682] - AccessToken: support Hash-based verb-dependent token transmission mode (e.g., `{get: :query, post: :header}`)
[gh!682]: https://github.com/ruby-oauth/oauth2/pull/682
diff --git a/README.md b/README.md
index 190f2420..74069300 100644
--- a/README.md
+++ b/README.md
@@ -1107,16 +1107,16 @@ resp = access.get("/v1/protected")
```
Notes:
-- Files must contain the appropriate PEMs. The private key may be encrypted; if so, pass a password to OpenSSL::PKey::RSA.new(File.read(path), ENV["KEY_PASSWORD"]).
+- Files must contain the appropriate PEMs. The private key may be encrypted; if so, pass a password to `OpenSSL::PKey::RSA.new(File.read(path), ENV["KEY_PASSWORD"])`.
- If your certificate and key are in a PKCS#12/PFX bundle, you can load them like:
- - p12 = OpenSSL::PKCS12.new(File.read("client.p12"), ENV["P12_PASSWORD"])
- - client_cert = p12.certificate; client_key = p12.key
+ - `p12 = OpenSSL::PKCS12.new(File.read("client.p12"), ENV["P12_PASSWORD"])`
+ - `client_cert = p12.certificate; client_key = p12.key`
- Server trust:
- - If your environment does not have system CAs, specify ca_file or ca_path inside the ssl: hash.
- - Keep verify: true in production. Set verify: false only for local testing.
-- Faraday adapter: Any adapter that supports Ruby’s OpenSSL should work. net_http (default) and net_http_persistent are common choices.
+ - If your environment does not have system CAs, specify `ca_file` or `ca_path` inside the `ssl:` hash.
+ - Keep `verify: true` in production. Set `verify: false` only for local testing.
+- Faraday adapter: Any adapter that supports Ruby’s OpenSSL should work. `net_http` (default) and `net_http_persistent` are common choices.
- Scope of mTLS: The SSL client cert is applied to any HTTPS request made by this client (token and resource requests) to the configured site base URL (and absolute URLs you call with the same client).
-- OIDC tie-in: Some OPs require tls_client_auth at the token endpoint per OIDC/OAuth specifications. That is enabled via auth_scheme: :tls_client_auth as shown above.
+- OIDC tie-in: Some OPs require tls_client_auth at the token endpoint per OIDC/OAuth specifications. That is enabled via `auth_scheme: :tls_client_auth` as shown above.
#### Authentication schemes for the token request
diff --git a/lib/oauth2/access_token.rb b/lib/oauth2/access_token.rb
index c428c019..8c68e321 100644
--- a/lib/oauth2/access_token.rb
+++ b/lib/oauth2/access_token.rb
@@ -134,7 +134,7 @@ def no_tokens_warning(hash, key)
# @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, 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
+ # (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
#
diff --git a/lib/oauth2/strategy/assertion.rb b/lib/oauth2/strategy/assertion.rb
index 6396fd6d..0515b26b 100644
--- a/lib/oauth2/strategy/assertion.rb
+++ b/lib/oauth2/strategy/assertion.rb
@@ -66,8 +66,8 @@ def authorize_url
# @see https://datatracker.ietf.org/doc/html/rfc7518#section-3.1
#
# The object type of `:key` may depend on the value of `:algorithm`. Sample arguments:
- # get_token(claim_set, {:algorithm => 'HS256', :key => 'secret_key'})
- # get_token(claim_set, {:algorithm => 'RS256', :key => OpenSSL::PKCS12.new(File.read('my_key.p12'), 'not_secret')})
+ # `get_token(claim_set, {:algorithm => 'HS256', :key => 'secret_key'})`
+ # `get_token(claim_set, {:algorithm => 'RS256', :key => OpenSSL::PKCS12.new(File.read('my_key.p12'), 'not_secret')})`
#
# @param [Hash] request_opts options that will be used to assemble the request
# @option request_opts [String] :scope the url parameter `scope` that may be required by some endpoints
From 3ae1da5f71c46aed47dda4d310fc9b1298f394da Mon Sep 17 00:00:00 2001
From: "Peter H. Boling"
Date: Fri, 7 Nov 2025 17:04:12 -0700
Subject: [PATCH 04/14] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20deps?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Gemfile.lock | 60 ++++++++++++++++++++++++++++------------------------
1 file changed, 32 insertions(+), 28 deletions(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index fa30a8d1..9961d0f9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -35,16 +35,16 @@ GEM
ast (2.4.3)
backports (3.25.2)
base64 (0.3.0)
- benchmark (0.4.1)
- bigdecimal (3.2.3)
+ benchmark (0.5.0)
+ bigdecimal (3.3.1)
bundler-audit (0.9.2)
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
concurrent-ruby (1.3.5)
- crack (1.0.0)
+ crack (1.0.1)
bigdecimal
rexml
- date (3.4.1)
+ date (3.5.0)
debug (1.11.0)
irb (~> 1.10)
reline (>= 0.3.8)
@@ -81,13 +81,13 @@ GEM
dry-inflector (~> 1.0)
dry-logic (~> 1.4)
zeitwerk (~> 2.6)
- erb (5.0.2)
+ erb (5.1.3)
faraday (2.14.0)
faraday-net_http (>= 2.0, < 3.5)
json
logger
- faraday-net_http (3.4.1)
- net-http (>= 0.5.0)
+ faraday-net_http (3.4.2)
+ net-http (~> 0.5)
gem_bench (2.0.5)
bundler (>= 1.14)
version_gem (~> 1.1, >= 1.1.4)
@@ -96,14 +96,14 @@ GEM
hashdiff (1.2.1)
hashie (5.0.0)
io-console (0.8.1)
- irb (1.15.2)
+ irb (1.15.3)
pp (>= 0.6.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
- json (2.15.0)
+ json (2.16.0)
jwt (3.1.2)
base64
- kettle-dev (1.1.31)
+ kettle-dev (1.1.49)
kettle-soup-cover (1.0.10)
simplecov (~> 0.22)
simplecov-cobertura (~> 3.0)
@@ -113,15 +113,17 @@ GEM
simplecov-rcov (~> 0.3, >= 0.3.7)
simplecov_json_formatter (~> 0.1, >= 0.1.4)
version_gem (~> 1.1, >= 1.1.8)
- kettle-test (1.0.3)
+ kettle-test (1.0.6)
appraisal2 (~> 3.0)
+ backports (~> 3.0)
rspec (~> 3.0)
rspec-block_is_expected (~> 1.0, >= 1.0.6)
+ rspec-pending_for (~> 0.1, >= 0.1.19)
rspec-stubbed_env (~> 1.0, >= 1.0.4)
rspec_junit_formatter (~> 0.6)
silent_stream (~> 1.0, >= 1.0.12)
timecop-rspec (~> 1.0, >= 1.0.3)
- version_gem (~> 1.1, >= 1.1.8)
+ version_gem (~> 1.1, >= 1.1.9)
kramdown (2.5.1)
rexml (>= 3.3.9)
kramdown-parser-gfm (1.1.0)
@@ -132,33 +134,34 @@ GEM
multi_xml (0.7.2)
bigdecimal (~> 3.1)
mutex_m (0.3.0)
- net-http (0.6.0)
+ net-http (0.7.0)
uri
nkf (0.2.0)
nokogiri (1.18.10-x86_64-linux-gnu)
racc (~> 1.4)
ostruct (0.6.3)
parallel (1.27.0)
- parser (3.3.9.0)
+ parser (3.3.10.0)
ast (~> 2.4.1)
racc
- pp (0.6.2)
+ pp (0.6.3)
prettyprint
prettyprint (0.2.0)
- prism (1.5.1)
+ prism (1.6.0)
psych (5.2.6)
date
stringio
public_suffix (6.0.2)
racc (1.8.1)
- rack (3.2.1)
+ rack (3.2.4)
rainbow (3.1.1)
- rake (13.3.0)
+ rake (13.3.1)
rbs (3.9.5)
logger
- rdoc (6.14.2)
+ rdoc (6.15.1)
erb
psych (>= 4.0.0)
+ tsort
reek (6.5.0)
dry-schema (~> 1.13)
logger (~> 1.6)
@@ -171,17 +174,17 @@ GEM
require_bench (1.0.4)
version_gem (>= 1.1.3, < 4)
rexml (3.4.4)
- rspec (3.13.1)
+ rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-block_is_expected (1.0.6)
- rspec-core (3.13.5)
+ rspec-core (3.13.6)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
- rspec-mocks (3.13.5)
+ rspec-mocks (3.13.7)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-pending_for (0.1.19)
@@ -245,7 +248,7 @@ GEM
rubocop-thread_safety (~> 0.5, >= 0.5.1)
standard-rubocop-lts (~> 1.0, >= 1.0.7)
version_gem (>= 1.1.3, < 3)
- rubocop-shopify (2.17.1)
+ rubocop-shopify (2.18.0)
rubocop (~> 1.62)
rubocop-thread_safety (0.7.3)
lint_roller (~> 1.1)
@@ -294,8 +297,8 @@ GEM
standard-custom (>= 1.0.2, < 2)
standard-performance (>= 1.3.1, < 2)
version_gem (>= 1.1.4, < 3)
- stone_checksums (1.0.2)
- version_gem (~> 1.1, >= 1.1.8)
+ stone_checksums (1.0.3)
+ version_gem (~> 1.1, >= 1.1.9)
stringio (3.1.7)
terminal-table (4.0.0)
unicode-display_width (>= 1.1.1, < 4)
@@ -305,14 +308,15 @@ GEM
delegate (~> 0.1)
rspec (~> 3.0)
timecop (>= 0.7, < 1)
+ tsort (0.2.0)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.1.0)
- uri (1.0.3)
+ uri (1.1.1)
vcr (6.3.1)
base64
version_gem (1.1.9)
- webmock (3.25.1)
+ webmock (3.26.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
@@ -320,7 +324,7 @@ GEM
yard-relative_markdown_links (0.5.0)
nokogiri (>= 1.14.3, < 2)
zeitwerk (2.7.3)
- zlib (3.2.1)
+ zlib (3.2.2)
PLATFORMS
x86_64-linux
From 23f9af35cb0dc2d5f12a76adef7ce12ca131e583 Mon Sep 17 00:00:00 2001
From: "Peter H. Boling"
Date: Fri, 7 Nov 2025 17:04:16 -0700
Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=8E=A8=20Template=20bootstrap=20by?=
=?UTF-8?q?=20kettle-dev-setup=20v1.1.49?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.git-hooks/commit-msg | 56 +--
.git-hooks/footer-template.erb.txt | 2 +-
.git-hooks/prepare-commit-msg | 17 +-
.github/workflows/current.yml | 40 +-
.github/workflows/dep-heads.yml | 40 +-
.github/workflows/heads.yml | 36 +-
.github/workflows/legacy.yml | 4 +-
.github/workflows/style.yml | 2 +
.github/workflows/truffle.yml | 12 +-
.gitignore | 1 +
.junie/guidelines.md | 13 +-
.yard_gfm_support.rb | 34 --
.yardopts | 9 +-
Appraisal.root.gemfile | 2 +-
Appraisals | 119 +++---
CONTRIBUTING.md | 35 +-
FUNDING.md | 17 +-
Gemfile | 4 +-
Gemfile.lock | 26 +-
README.md | 364 +++++-------------
Rakefile | 2 +-
gemfiles/modular/documentation.gemfile | 1 +
gemfiles/modular/erb/r2.3/default.gemfile | 2 +-
gemfiles/modular/optional.gemfile | 1 +
gemfiles/modular/x_std_libs/r2.4/libs.gemfile | 2 +-
oauth2.gemspec | 24 +-
test_gfm.rb | 32 --
27 files changed, 351 insertions(+), 546 deletions(-)
delete mode 100644 .yard_gfm_support.rb
delete mode 100644 test_gfm.rb
diff --git a/.git-hooks/commit-msg b/.git-hooks/commit-msg
index 750c5bb1..5d160e67 100755
--- a/.git-hooks/commit-msg
+++ b/.git-hooks/commit-msg
@@ -16,33 +16,39 @@ begin
# Is the first character a GitMoji?
gitmoji_index = full_text =~ Gitmoji::Regex::REGEX
if gitmoji_index == 0
- exit 0
+ exit(0)
else
- denied = < e
- warn("gitmoji-regex gem not found: #{e.class}: #{e.message}.\n\tSkipping gitmoji check and allowing commit to proceed.\n\tRecommendation: add 'gitmoji-regex' to your development dependencies to enable this check.")
- exit 0
+ failure = <<~EOM
+ gitmoji-regex gem not found: #{e.class}: #{e.message}.
+ Skipping gitmoji check and allowing commit to proceed.
+ Recommendation: add 'gitmoji-regex' to your development dependencies to enable this check.
+
+ EOM
+ warn(failure)
+ exit(0)
end
diff --git a/.git-hooks/footer-template.erb.txt b/.git-hooks/footer-template.erb.txt
index d732d699..36cdb0ad 100644
--- a/.git-hooks/footer-template.erb.txt
+++ b/.git-hooks/footer-template.erb.txt
@@ -1,5 +1,5 @@
⚡️ A message from a fellow meat-based-AI ⚡️
-- [❤️] Finely-crafted open-source tools like <%= @gem_name %> (& many more) are a full-time endeavor.
+- [❤️] Finely-crafted open-source tools like <%= @gem_name %> (& many more) require time and effort.
- [❤️] Though I adore my work, it lacks financial sustainability.
- [❤️] Please, help me continue enhancing your tools by becoming a sponsor:
- [💲] https://liberapay.com/pboling/donate
diff --git a/.git-hooks/prepare-commit-msg b/.git-hooks/prepare-commit-msg
index c6a15570..dbc30589 100755
--- a/.git-hooks/prepare-commit-msg
+++ b/.git-hooks/prepare-commit-msg
@@ -3,17 +3,6 @@
# Fail on error and unset variables
set -eu
-# Determine project root as the parent directory of this hook script
-PROJECT_ROOT="$(CDPATH= cd -- "$(dirname -- "$0")"/.. && pwd)"
-
-# Run the Ruby hook within the direnv context (if available),
-# so ENV from .envrc/.env.local at project root is loaded.
-# One of the things .envrc needs to do is add $PROJECT_ROOT/bin/ to the path.
-# You should have this line at the top of .envrc
-# PATH_add bin
-# NOTE: If this project ships exe scripts it should also add that.
-if command -v direnv >/dev/null 2>&1; then
- exec direnv exec "$PROJECT_ROOT" "kettle-commit-msg" "$@"
-else
- raise "direnv not found. Local development of this project ($PROJECT_ROOT) with tools from the kettle-dev gem may not work properly. Please run 'brew install direnv'."
-fi
+# We are not using direnv exec here because mise and direnv can result in conflicting PATH settings:
+# See: https://mise.jdx.dev/direnv.html
+exec "kettle-commit-msg" "$@"
diff --git a/.github/workflows/current.yml b/.github/workflows/current.yml
index f8a9e644..7dab87e0 100644
--- a/.github/workflows/current.yml
+++ b/.github/workflows/current.yml
@@ -63,11 +63,11 @@ jobs:
steps:
- name: Checkout
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
uses: actions/checkout@v5
- name: Setup Ruby & RubyGems
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
@@ -79,11 +79,37 @@ jobs:
# We need to do this first to get appraisal installed.
# NOTE: This does not use the primary Gemfile at all.
- name: Install Root Appraisal
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle
- - name: Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+
+ - name: "[Attempt 1] Install Root Appraisal"
+ id: bundleAttempt1
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
+ run: bundle
+ # Continue to the next step on failure
+ continue-on-error: true
+
+ # Effectively an automatic retry of the previous step.
+ - name: "[Attempt 2] Install Root Appraisal"
+ id: bundleAttempt2
+ # If bundleAttempt1 failed, try again here; Otherwise skip.
+ if: ${{ steps.bundleAttempt1.outcome == 'failure' && (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
+ run: bundle
+
+ - name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
+ id: bundleAppraisalAttempt1
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
+ run: bundle exec appraisal ${{ matrix.appraisal }} bundle
+ # Continue to the next step on failure
+ continue-on-error: true
+
+ # Effectively an automatic retry of the previous step.
+ - name: "[Attempt 2] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
+ id: bundleAppraisalAttempt2
+ # If bundleAppraisalAttempt1 failed, try again here; Otherwise skip.
+ if: ${{ steps.bundleAppraisalAttempt1.outcome == 'failure' && (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
- - name: Tests for ${{ matrix.ruby }}@${{ matrix.appraisal }} via ${{ matrix.exec_cmd }}
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+
+ - name: Tests for ${{ matrix.ruby }} via ${{ matrix.exec_cmd }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }}
diff --git a/.github/workflows/dep-heads.yml b/.github/workflows/dep-heads.yml
index f6915689..a3d03f5f 100644
--- a/.github/workflows/dep-heads.yml
+++ b/.github/workflows/dep-heads.yml
@@ -47,9 +47,7 @@ jobs:
rubygems: latest
bundler: latest
- # truffleruby-24.1
- # (according to documentation: targets Ruby 3.3 compatibility)
- # (according to runtime: targets Ruby 3.2 compatibility)
+ # truffleruby-24.1 (targets Ruby 3.3 compatibility)
- ruby: "truffleruby"
appraisal: "dep-heads"
exec_cmd: "rake test"
@@ -67,11 +65,11 @@ jobs:
steps:
- name: Checkout
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
uses: actions/checkout@v5
- name: Setup Ruby & RubyGems
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
@@ -82,24 +80,38 @@ jobs:
# Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root)
# We need to do this first to get appraisal installed.
# NOTE: This does not use the primary Gemfile at all.
- - name: "Install Root Appraisal"
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ - name: Install Root Appraisal
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle
- - name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ - name: "[Attempt 1] Install Root Appraisal"
id: bundleAttempt1
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
+ run: bundle
+ # Continue to the next step on failure
+ continue-on-error: true
+
+ # Effectively an automatic retry of the previous step.
+ - name: "[Attempt 2] Install Root Appraisal"
+ id: bundleAttempt2
+ # If bundleAttempt1 failed, try again here; Otherwise skip.
+ if: ${{ steps.bundleAttempt1.outcome == 'failure' && (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
+ run: bundle
+
+ - name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
+ id: bundleAppraisalAttempt1
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
# Continue to the next step on failure
continue-on-error: true
# Effectively an automatic retry of the previous step.
- name: "[Attempt 2] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
- # If bundleAttempt1 failed, try again here; Otherwise skip.
- if: ${{ steps.bundleAttempt1.outcome == 'failure' && !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
- id: bundleAttempt2
+ id: bundleAppraisalAttempt2
+ # If bundleAppraisalAttempt1 failed, try again here; Otherwise skip.
+ if: ${{ steps.bundleAppraisalAttempt1.outcome == 'failure' && (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
- - name: Tests for ${{ matrix.ruby }}@${{ matrix.appraisal }} via ${{ matrix.exec_cmd }}
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ - name: Tests for ${{ matrix.ruby }} via ${{ matrix.exec_cmd }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }}
diff --git a/.github/workflows/heads.yml b/.github/workflows/heads.yml
index f8c92d16..104f1a7a 100644
--- a/.github/workflows/heads.yml
+++ b/.github/workflows/heads.yml
@@ -64,11 +64,11 @@ jobs:
steps:
- name: Checkout
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
uses: actions/checkout@v5
- name: Setup Ruby & RubyGems
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
@@ -79,24 +79,38 @@ jobs:
# Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root)
# We need to do this first to get appraisal installed.
# NOTE: This does not use the primary Gemfile at all.
- - name: "Install Root Appraisal"
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ - name: Install Root Appraisal
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle
- - name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ - name: "[Attempt 1] Install Root Appraisal"
id: bundleAttempt1
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
+ run: bundle
+ # Continue to the next step on failure
+ continue-on-error: true
+
+ # Effectively an automatic retry of the previous step.
+ - name: "[Attempt 2] Install Root Appraisal"
+ id: bundleAttempt2
+ # If bundleAttempt1 failed, try again here; Otherwise skip.
+ if: ${{ steps.bundleAttempt1.outcome == 'failure' && (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
+ run: bundle
+
+ - name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
+ id: bundleAppraisalAttempt1
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
# Continue to the next step on failure
continue-on-error: true
# Effectively an automatic retry of the previous step.
- name: "[Attempt 2] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
- # If bundleAttempt1 failed, try again here; Otherwise skip.
- if: ${{ steps.bundleAttempt1.outcome == 'failure' && !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
- id: bundleAttempt2
+ id: bundleAppraisalAttempt2
+ # If bundleAppraisalAttempt1 failed, try again here; Otherwise skip.
+ if: ${{ steps.bundleAppraisalAttempt1.outcome == 'failure' && (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
- - name: Tests for ${{ matrix.ruby }}@${{ matrix.appraisal }} via ${{ matrix.exec_cmd }}
- if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }}
+ - name: Tests for ${{ matrix.ruby }} via ${{ matrix.exec_cmd }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }}
diff --git a/.github/workflows/legacy.yml b/.github/workflows/legacy.yml
index 7f1fc299..f7853f62 100644
--- a/.github/workflows/legacy.yml
+++ b/.github/workflows/legacy.yml
@@ -50,8 +50,8 @@ jobs:
appraisal: "ruby-3-1"
exec_cmd: "rake test"
gemfile: "Appraisal.root"
- rubygems: latest
- bundler: latest
+ rubygems: '3.6.9'
+ bundler: '2.6.9'
steps:
- name: Checkout
diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml
index 2fe1e03c..4fbef86e 100644
--- a/.github/workflows/style.yml
+++ b/.github/workflows/style.yml
@@ -63,3 +63,5 @@ jobs:
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
- name: Run ${{ matrix.appraisal }} checks via ${{ matrix.exec_cmd }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }}
+ - name: Validate RBS Types
+ run: bundle exec appraisal ${{ matrix.appraisal }} bin/rbs validate
diff --git a/.github/workflows/truffle.yml b/.github/workflows/truffle.yml
index db651885..67807231 100644
--- a/.github/workflows/truffle.yml
+++ b/.github/workflows/truffle.yml
@@ -47,9 +47,11 @@ jobs:
steps:
- name: Checkout
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
uses: actions/checkout@v5
- name: Setup Ruby & RubyGems
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
@@ -61,10 +63,12 @@ jobs:
# We need to do this first to get appraisal installed.
# NOTE: This does not use the primary Gemfile at all.
- name: Install Root Appraisal
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle
- name: "[Attempt 1] Install Root Appraisal"
id: bundleAttempt1
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle
# Continue to the next step on failure
continue-on-error: true
@@ -73,11 +77,12 @@ jobs:
- name: "[Attempt 2] Install Root Appraisal"
id: bundleAttempt2
# If bundleAttempt1 failed, try again here; Otherwise skip.
- if: steps.bundleAttempt1.outcome == 'failure'
+ if: ${{ steps.bundleAttempt1.outcome == 'failure' && (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle
- name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
id: bundleAppraisalAttempt1
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
# Continue to the next step on failure
continue-on-error: true
@@ -85,9 +90,10 @@ jobs:
# Effectively an automatic retry of the previous step.
- name: "[Attempt 2] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
id: bundleAppraisalAttempt2
- # If bundleAttempt1 failed, try again here; Otherwise skip.
- if: steps.bundleAppraisalAttempt1.outcome == 'failure'
+ # If bundleAppraisalAttempt1 failed, try again here; Otherwise skip.
+ if: ${{ steps.bundleAppraisalAttempt1.outcome == 'failure' && (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
- name: Tests for ${{ matrix.ruby }} via ${{ matrix.exec_cmd }}
+ if: ${{ (env.ACT && !(startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) || (!env.ACT && (startsWith(matrix.ruby, 'jruby')) || startsWith(matrix.ruby, 'truffleruby')) }}
run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }}
diff --git a/.gitignore b/.gitignore
index 15f1f941..068190dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
*.gem
# Bundler
+/vendor/bundle/
/.bundle/
/gemfiles/*.lock
/gemfiles/.bundle/
diff --git a/.junie/guidelines.md b/.junie/guidelines.md
index 152e080b..42844a0a 100644
--- a/.junie/guidelines.md
+++ b/.junie/guidelines.md
@@ -47,9 +47,7 @@ This document captures project-specific knowledge to streamline setup, testing,
- RSpec 3.13 with custom spec/spec_helper.rb configuration:
- silent_stream: STDOUT is silenced by default for examples to keep logs clean.
- To explicitly test console output, tag the example or group with :check_output.
- - Global state hygiene: Around each example, FlossFunding.namespaces and FlossFunding.silenced are snapshotted and restored to prevent cross-test pollution.
- DEBUG toggle: Set DEBUG=true to require 'debug' and avoid silencing output during your run.
- - ENV seeding: The suite sets ENV["FLOSS_FUNDING_FLOSS_FUNDING"] = "Free-as-in-beer" so that the library’s own namespace is considered activated (avoids noisy warnings).
- Coverage: kettle-soup-cover integrates SimpleCov; .simplecov is invoked from spec_helper when enabled by Kettle::Soup::Cover::DO_COV, which is controlled by K_SOUP_COV_DO being set to true / false.
- RSpec.describe usage:
- Use `describe "#"` to contain a block of specs that test instance method behavior.
@@ -73,10 +71,11 @@ This document captures project-specific knowledge to streamline setup, testing,
- Output visibility
- To see STDOUT from the code under test, use the :check_output tag on the example or group.
Example:
- RSpec.describe "output", :check_output do
- it "prints" do
- puts "This output should be visible"
- expect(true).to be true
+ RSpec.describe "with output", :check_output do
+ it "has output" do
+ output = capture(:stderr) {kernel.warn("This is a warning")}
+ logs = [ "This is a warning\n" ]
+ expect(output).to(include(*logs))
end
end
- Alternatively, run with DEBUG=true to disable silencing for the entire run.
@@ -94,7 +93,9 @@ This document captures project-specific knowledge to streamline setup, testing,
include_context 'with stubbed env'
- in a before hook, or in an example:
stub_env("FLOSS_FUNDING_MY_NS" => "Free-as-in-beer")
+
# example code continues
+
- If your spec needs to assert on console output, tag it with :check_output. By default, STDOUT is silenced.
- Use Timecop for deterministic time-sensitive behavior as needed (require config/timecop is already done by spec_helper).
diff --git a/.yard_gfm_support.rb b/.yard_gfm_support.rb
deleted file mode 100644
index 3c8a6b0e..00000000
--- a/.yard_gfm_support.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Gratefully and liberally taken from the MIT-licensed https://github.com/bensheldon/good_job/pull/113/files
-require "kramdown"
-require "kramdown-parser-gfm"
-
-# Custom markup provider class that always renders Kramdown using GFM (Github Flavored Markdown).
-# GFM is needed to render markdown tables and fenced code blocks in the README.
-class KramdownGfmDocument < Kramdown::Document
- def initialize(source, options = {})
- options[:input] = "GFM" unless options.key?(:input)
- super(source, options)
- end
-end
-
-# Ensure YARD is loaded before modifying its constants
-require 'yard' unless defined?(YARD)
-
-# Insert the new provider as the highest priority option for Markdown.
-# See:
-# - https://github.com/lsegal/yard/issues/1157
-# - https://github.com/lsegal/yard/issues/1017
-# - https://github.com/lsegal/yard/blob/main/lib/yard/templates/helpers/markup_helper.rb
-require 'yard/templates/helpers/markup_helper'
-
-providers = YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown]
-providers.unshift({lib: :kramdown, const: :KramdownGfmDocument})
-
-# Normalize provider entries to what YARD expects (const must be a String)
-providers.each do |provider|
- const = provider[:const]
- provider[:const] = const.to_s if const.is_a?(Symbol)
-end
-
-# De-duplicate entries by [lib, const]
-providers.uniq! { |p| [p[:lib], p[:const].to_s] }
diff --git a/.yardopts b/.yardopts
index 479134df..ab259161 100644
--- a/.yardopts
+++ b/.yardopts
@@ -1,11 +1,12 @@
+--plugin fence
+-e yard/fence/hoist.rb
--plugin junk
--plugin relative_markdown_links
---readme README.md
+--readme tmp/yard-fence/README.md
--charset utf-8
--markup markdown
--output docs
---load .yard_gfm_support.rb
'lib/**/*.rb'
-
-'*.md'
-'*.txt'
\ No newline at end of file
+'tmp/yard-fence/*.md'
+'tmp/yard-fence/*.txt'
diff --git a/Appraisal.root.gemfile b/Appraisal.root.gemfile
index 02afd183..a0001cd0 100644
--- a/Appraisal.root.gemfile
+++ b/Appraisal.root.gemfile
@@ -2,7 +2,7 @@
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
-source "https://rubygems.org"
+source "https://gem.coop"
# Appraisal Root Gemfile is for running appraisal to generate the Appraisal Gemfiles
# in gemfiles/*gemfile.
diff --git a/Appraisals b/Appraisals
index 90e5effc..e1a741b5 100644
--- a/Appraisals
+++ b/Appraisals
@@ -47,65 +47,6 @@ appraise "dep-heads" do
eval_gemfile "modular/runtime_heads.gemfile"
end
-appraise "ruby-2-3-hashie_v0" do
- eval_gemfile "modular/faraday_v0.gemfile"
- eval_gemfile "modular/hashie_v0.gemfile"
- eval_gemfile "modular/jwt_v1.gemfile"
- eval_gemfile "modular/logger_v1_2.gemfile"
- eval_gemfile "modular/multi_xml_v0_5.gemfile"
- eval_gemfile "modular/rack_v1_2.gemfile"
- eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
-end
-
-appraise "ruby-2-3-hashie_v1" do
- eval_gemfile "modular/faraday_v0.gemfile"
- eval_gemfile "modular/hashie_v1.gemfile"
- eval_gemfile "modular/jwt_v1.gemfile"
- eval_gemfile "modular/logger_v1_2.gemfile"
- eval_gemfile "modular/multi_xml_v0_5.gemfile"
- eval_gemfile "modular/rack_v1_2.gemfile"
- eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
-end
-
-appraise "ruby-2-3-hashie_v2" do
- eval_gemfile "modular/faraday_v0.gemfile"
- eval_gemfile "modular/hashie_v2.gemfile"
- eval_gemfile "modular/jwt_v1.gemfile"
- eval_gemfile "modular/logger_v1_2.gemfile"
- eval_gemfile "modular/multi_xml_v0_5.gemfile"
- eval_gemfile "modular/rack_v1_2.gemfile"
- eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
-end
-
-appraise "ruby-2-3-hashie_v3" do
- eval_gemfile "modular/faraday_v0.gemfile"
- eval_gemfile "modular/hashie_v3.gemfile"
- eval_gemfile "modular/jwt_v1.gemfile"
- eval_gemfile "modular/logger_v1_2.gemfile"
- eval_gemfile "modular/multi_xml_v0_5.gemfile"
- eval_gemfile "modular/rack_v1_2.gemfile"
- eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
-end
-
-appraise "ruby-2-3-hashie_v4" do
- eval_gemfile "modular/faraday_v0.gemfile"
- eval_gemfile "modular/hashie_v4.gemfile"
- eval_gemfile "modular/jwt_v1.gemfile"
- eval_gemfile "modular/logger_v1_2.gemfile"
- eval_gemfile "modular/multi_xml_v0_5.gemfile"
- eval_gemfile "modular/rack_v1_2.gemfile"
- eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
-end
-
-appraise "ruby-2-3-hashie_v5" do
- eval_gemfile "modular/faraday_v0.gemfile"
- eval_gemfile "modular/hashie_v5.gemfile"
- eval_gemfile "modular/jwt_v1.gemfile"
- eval_gemfile "modular/logger_v1_2.gemfile"
- eval_gemfile "modular/multi_xml_v0_5.gemfile"
- eval_gemfile "modular/rack_v1_2.gemfile"
- eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
-end
appraise "ruby-2-4" do
eval_gemfile "modular/faraday_v1.gemfile"
@@ -217,3 +158,63 @@ appraise "style" do
eval_gemfile "modular/style.gemfile"
eval_gemfile "modular/x_std_libs.gemfile"
end
+
+appraise "ruby-2-3-hashie_v0" do
+ eval_gemfile "modular/faraday_v0.gemfile"
+ eval_gemfile "modular/hashie_v0.gemfile"
+ eval_gemfile "modular/jwt_v1.gemfile"
+ eval_gemfile "modular/logger_v1_2.gemfile"
+ eval_gemfile "modular/multi_xml_v0_5.gemfile"
+ eval_gemfile "modular/rack_v1_2.gemfile"
+ eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
+end
+
+appraise "ruby-2-3-hashie_v1" do
+ eval_gemfile "modular/faraday_v0.gemfile"
+ eval_gemfile "modular/hashie_v1.gemfile"
+ eval_gemfile "modular/jwt_v1.gemfile"
+ eval_gemfile "modular/logger_v1_2.gemfile"
+ eval_gemfile "modular/multi_xml_v0_5.gemfile"
+ eval_gemfile "modular/rack_v1_2.gemfile"
+ eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
+end
+
+appraise "ruby-2-3-hashie_v2" do
+ eval_gemfile "modular/faraday_v0.gemfile"
+ eval_gemfile "modular/hashie_v2.gemfile"
+ eval_gemfile "modular/jwt_v1.gemfile"
+ eval_gemfile "modular/logger_v1_2.gemfile"
+ eval_gemfile "modular/multi_xml_v0_5.gemfile"
+ eval_gemfile "modular/rack_v1_2.gemfile"
+ eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
+end
+
+appraise "ruby-2-3-hashie_v3" do
+ eval_gemfile "modular/faraday_v0.gemfile"
+ eval_gemfile "modular/hashie_v3.gemfile"
+ eval_gemfile "modular/jwt_v1.gemfile"
+ eval_gemfile "modular/logger_v1_2.gemfile"
+ eval_gemfile "modular/multi_xml_v0_5.gemfile"
+ eval_gemfile "modular/rack_v1_2.gemfile"
+ eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
+end
+
+appraise "ruby-2-3-hashie_v4" do
+ eval_gemfile "modular/faraday_v0.gemfile"
+ eval_gemfile "modular/hashie_v4.gemfile"
+ eval_gemfile "modular/jwt_v1.gemfile"
+ eval_gemfile "modular/logger_v1_2.gemfile"
+ eval_gemfile "modular/multi_xml_v0_5.gemfile"
+ eval_gemfile "modular/rack_v1_2.gemfile"
+ eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
+end
+
+appraise "ruby-2-3-hashie_v5" do
+ eval_gemfile "modular/faraday_v0.gemfile"
+ eval_gemfile "modular/hashie_v5.gemfile"
+ eval_gemfile "modular/jwt_v1.gemfile"
+ eval_gemfile "modular/logger_v1_2.gemfile"
+ eval_gemfile "modular/multi_xml_v0_5.gemfile"
+ eval_gemfile "modular/rack_v1_2.gemfile"
+ eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile"
+end
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f70f8c81..4cbdfb9b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -24,9 +24,10 @@ Follow these instructions:
## Executables vs Rake tasks
-Executables shipped by oauth2 can be used with or without generating the binstubs.
-They will work when oauth2 is installed globally (i.e., `gem install oauth2`) and do not require that oauth2 be in your bundle.
+Executables shipped by dependencies, such as kettle-dev, and stone_checksums, are available
+after running `bin/setup`. These include:
+- gem_checksums
- kettle-changelog
- kettle-commit-msg
- oauth2-setup
@@ -35,20 +36,10 @@ They will work when oauth2 is installed globally (i.e., `gem install oauth2`) an
- kettle-readme-backers
- kettle-release
-However, the rake tasks provided by oauth2 do require oauth2 to be added as a development dependency and loaded in your Rakefile.
-See the full list of rake tasks in head of Rakefile
+There are many Rake tasks available as well. You can see them by running:
-**Gemfile**
-```ruby
-group :development do
- gem "oauth2", require: false
-end
-```
-
-**Rakefile**
-```ruby
-# Rakefile
-require "oauth2"
+```shell
+bin/rake -T
```
## Environment Variables for Local Development
@@ -118,10 +109,8 @@ bundle exec rake test
### Spec organization (required)
-- One spec file per class/module. For each class or module under `lib/`, keep all of its unit tests in a single spec file under `spec/` that mirrors the path and file name exactly: `lib/oauth2/release_cli.rb` -> `spec/oauth2/release_cli_spec.rb`.
-- Never add a second spec file for the same class/module. Examples of disallowed names: `*_more_spec.rb`, `*_extra_spec.rb`, `*_status_spec.rb`, or any other suffix that still targets the same class. If you find yourself wanting a second file, merge those examples into the canonical spec file for that class/module.
+- One spec file per class/module. For each class or module under `lib/`, keep all of its unit tests in a single spec file under `spec/` that mirrors the path and file name exactly: `lib/oauth2/my_class.rb` -> `spec/oauth2/my_class_spec.rb`.
- Exception: Integration specs that intentionally span multiple classes. Place these under `spec/integration/` (or a clearly named integration folder), and do not directly mirror a single class. Name them after the scenario, not a class.
-- Migration note: If a duplicate spec file exists, move all examples into the canonical file and delete the duplicate. Do not leave stubs or empty files behind.
## Lint It
@@ -144,7 +133,7 @@ For more detailed information about using RuboCop in this project, please see th
Never add `# rubocop:disable ...` / `# rubocop:enable ...` comments to code or specs (except when following the few existing `rubocop:disable` patterns for a rule already being disabled elsewhere in the code). Instead:
- Prefer configuration-based exclusions when a rule should not apply to certain paths or files (e.g., via `.rubocop.yml`).
-- When a violation is temporary and you plan to fix it later, record it in `.rubocop_gradual.lock` using the gradual workflow:
+- When a violation is temporary, and you plan to fix it later, record it in `.rubocop_gradual.lock` using the gradual workflow:
- `bundle exec rake rubocop_gradual:autocorrect` (preferred)
- `bundle exec rake rubocop_gradual:force_update` (only when you cannot fix the violations immediately)
@@ -167,7 +156,7 @@ Also see GitLab Contributors: [https://gitlab.com/ruby-oauth/oauth2/-/graphs/mai
**IMPORTANT**: To sign a build,
a public key for signing gems will need to be picked up by the line in the
`gemspec` defining the `spec.cert_chain` (check the relevant ENV variables there).
-All releases to RubyGems.org are signed releases.
+All releases are signed releases.
See: [RubyGems Security Guide][🔒️rubygems-security-guide]
NOTE: To build without signing the gem set `SKIP_GEM_SIGNING` to any value in the environment.
@@ -176,7 +165,7 @@ NOTE: To build without signing the gem set `SKIP_GEM_SIGNING` to any value in th
#### Automated process
-1. Update version.rb to contian the correct version-to-be-released.
+1. Update version.rb to contain the correct version-to-be-released.
2. Run `bundle exec kettle-changelog`.
3. Run `bundle exec kettle-release`.
@@ -205,7 +194,7 @@ NOTE: To build without signing the gem set `SKIP_GEM_SIGNING` to any value in th
12. Sanity check the SHA256, comparing with the output from the `bin/gem_checksums` command:
- `sha256sum pkg/-.gem`
13. 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][💎rubygems]
+ push git commits and tags, and push the `.gem` file to the gem host configured in the gemspec.
[📜src-gl]: https://gitlab.com/ruby-oauth/oauth2/
[📜src-cb]: https://codeberg.org/ruby-oauth/oauth2
@@ -216,7 +205,7 @@ NOTE: To build without signing the gem set `SKIP_GEM_SIGNING` to any value in th
[🖐contributors]: https://github.com/ruby-oauth/oauth2/graphs/contributors
[🚎contributors-gl]: https://gitlab.com/ruby-oauth/oauth2/-/graphs/main
[🖐contributors-img]: https://contrib.rocks/image?repo=ruby-oauth/oauth2
-[💎rubygems]: https://rubygems.org
+[💎gem-coop]: https://gem.coop
[🔒️rubygems-security-guide]: https://guides.rubygems.org/security/#building-gems
[🔒️rubygems-checksums-pr]: https://github.com/rubygems/rubygems/pull/6022
[🔒️rubygems-guides-pr]: https://github.com/rubygems/guides/pull/325
diff --git a/FUNDING.md b/FUNDING.md
index b7a061d1..5ddd4bca 100644
--- a/FUNDING.md
+++ b/FUNDING.md
@@ -6,7 +6,7 @@ Many paths lead to being a sponsor or a backer of this project. Are you on such
[![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal]
-[![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon]
+[![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
[⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
[⛳liberapay]: https://liberapay.com/pboling/donate
@@ -31,11 +31,11 @@ Many paths lead to being a sponsor or a backer of this project. Are you on such
-# 🤑 Request for Help
+# 🤑 A request for help
Maintainers have teeth and need to pay their dentists.
-After getting laid off in an RIF in March and filled with many dozens of rejections,
-I'm now spending ~60+ hours a week building open source tools.
+After getting laid off in an RIF in March, and encountering difficulty finding a new one,
+I began spending most of my time building open source tools.
I'm hoping to be able to pay for my kids' health insurance this month,
so if you value the work I am doing, I need your support.
Please consider sponsoring me or the project.
@@ -44,16 +44,13 @@ To join the community or get help 👇️ Join the Discord.
[![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
-To say "thanks for maintaining such a great tool" ☝️ Join the Discord or 👇️ send money.
+To say "thanks!" ☝️ Join the Discord or 👇️ send money.
-[![Sponsor ruby-oauth/oauth2 on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay-img] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal-img]
+[![Sponsor ruby-oauth/oauth2 on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
# Another Way to Support Open Source Software
-> How wonderful it is that nobody need wait a single moment before starting to improve the world.
->—Anne Frank
-
-I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions — totaling 79 hours of FLOSS coding over just the past seven days, a pretty regular week for me. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈 cats).
+I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈 cats).
If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in `bundle fund`.
diff --git a/Gemfile b/Gemfile
index 19875ab5..be6c1816 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-source "https://rubygems.org"
+source "https://gem.coop"
-git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
+git_source(:codeberg) { |repo_name| "https://codeberg.org/#{repo_name}" }
git_source(:gitlab) { |repo_name| "https://gitlab.com/#{repo_name}" }
#### IMPORTANT #######################################################
diff --git a/Gemfile.lock b/Gemfile.lock
index 9961d0f9..65ed6feb 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,5 +1,5 @@
GIT
- remote: https://github.com/pboling/yard-junk
+ remote: https://github.com/pboling/yard-junk.git
revision: 54ccebabbfa9a9cd44d0b991687ebbfd22c32b55
branch: next
specs:
@@ -23,7 +23,7 @@ PATH
version_gem (~> 1.1, >= 1.1.9)
GEM
- remote: https://rubygems.org/
+ remote: https://gem.coop/
specs:
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
@@ -41,9 +41,6 @@ GEM
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
concurrent-ruby (1.3.5)
- crack (1.0.1)
- bigdecimal
- rexml
date (3.5.0)
debug (1.11.0)
irb (~> 1.10)
@@ -93,7 +90,6 @@ GEM
version_gem (~> 1.1, >= 1.1.4)
gitmoji-regex (1.0.3)
version_gem (~> 1.1, >= 1.1.8)
- hashdiff (1.2.1)
hashie (5.0.0)
io-console (0.8.1)
irb (1.15.3)
@@ -313,14 +309,12 @@ GEM
unicode-emoji (~> 4.1)
unicode-emoji (4.1.0)
uri (1.1.1)
- vcr (6.3.1)
- base64
version_gem (1.1.9)
- webmock (3.26.1)
- addressable (>= 2.8.0)
- crack (>= 0.3.2)
- hashdiff (>= 0.4.0, < 2.0.0)
yard (0.9.37)
+ yard-fence (0.4.0)
+ rdoc (~> 6.11)
+ version_gem (~> 1.1, >= 1.1.9)
+ yard (~> 0.9, >= 0.9.37)
yard-relative_markdown_links (0.5.0)
nokogiri (>= 1.14.3, < 2)
zeitwerk (2.7.3)
@@ -330,7 +324,7 @@ PLATFORMS
x86_64-linux
DEPENDENCIES
- addressable (~> 2.8, >= 2.8.7)
+ addressable (~> 2.8, >= 2.8.7, >= 2.8, < 3)
appraisal2 (~> 3.0)
backports (~> 3.25, >= 3.25.1)
benchmark (~> 0.4, >= 0.4.1)
@@ -342,7 +336,7 @@ DEPENDENCIES
irb (~> 1.15, >= 1.15.2)
kettle-dev (~> 1.1)
kettle-soup-cover (~> 1.0, >= 1.0.10)
- kettle-test (~> 1.0)
+ kettle-test (~> 1.0, >= 1.0.6)
kramdown (~> 2.5, >= 2.5.1)
kramdown-parser-gfm (~> 1.1)
mutex_m (~> 0.2)
@@ -353,7 +347,6 @@ DEPENDENCIES
reek (~> 6.5)
require_bench (~> 1.0, >= 1.0.4)
rexml (~> 3.2, >= 3.2.5)
- rspec-pending_for (~> 0.0, >= 0.0.17)
rubocop-lts (~> 8.0)
rubocop-on-rbs (~> 1.8)
rubocop-packaging (~> 0.6, >= 0.6.0)
@@ -363,9 +356,8 @@ DEPENDENCIES
standard (>= 1.50)
stone_checksums (~> 1.0, >= 1.0.2)
stringio (>= 3.0)
- vcr (>= 4)
- webmock (>= 3)
yard (~> 0.9, >= 0.9.37)
+ yard-fence (~> 0.4)
yard-junk (~> 0.0, >= 0.0.10)!
yard-relative_markdown_links (~> 0.5.0)
diff --git a/README.md b/README.md
index 74069300..a5ec5975 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,32 @@
+| 📍 NOTE |
+|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| RubyGems (the [GitHub org][rubygems-org], not the website) [suffered][draper-security] a [hostile takeover][ellen-takeover] in September 2025. |
+| Ultimately [4 maintainers][simi-removed] were [hard removed][martin-removed] and a reason has been given for only 1 of those, while 2 others resigned in protest. |
+| It is a [complicated story][draper-takeover] which is difficult to [parse quickly][draper-lies]. |
+| I'm adding notes like this to gems because I [don't condone theft][draper-theft] of repositories or gems from their rightful owners. |
+| If a similar theft happened with my repos/gems, I'd hope some would stand up for me. |
+| Disenfranchised former-maintainers have started [gem.coop][gem-coop]. |
+| Once available I will publish there exclusively; unless RubyCentral makes amends with the community. |
+| The ["Technology for Humans: Joel Draper"][reinteractive-podcast] podcast episode by [reinteractive][reinteractive] is the most cogent summary I'm aware of. |
+| See [here][gem-naming], [here][gem-coop] and [here][martin-ann] for more info on what comes next. |
+| What I'm doing: A (WIP) proposal for [bundler/gem scopes][gem-scopes], and a (WIP) proposal for a federated [gem server][gem-server]. |
+
+[rubygems-org]: https://github.com/rubygems/
+[draper-security]: https://joel.drapper.me/p/ruby-central-security-measures/
+[draper-takeover]: https://joel.drapper.me/p/ruby-central-takeover/
+[ellen-takeover]: https://pup-e.com/blog/goodbye-rubygems/
+[simi-removed]: https://www.reddit.com/r/ruby/s/gOk42POCaV
+[martin-removed]: https://bsky.app/profile/martinemde.com/post/3m3occezxxs2q
+[draper-lies]: https://joel.drapper.me/p/ruby-central-fact-check/
+[draper-theft]: https://joel.drapper.me/p/ruby-central/
+[reinteractive]: https://reinteractive.com/ruby-on-rails
+[gem-coop]: https://gem.coop
+[gem-naming]: https://github.com/gem-coop/gem.coop/issues/12
+[martin-ann]: https://martinemde.com/2025/10/05/announcing-gem-coop.html
+[gem-scopes]: https://github.com/galtzo-floss/bundle-namespace
+[gem-server]: https://github.com/galtzo-floss/gem-server
+[reinteractive-podcast]: https://youtu.be/_H4qbtC5qzU?si=BvuBU90R2wAqD2E6
+
[![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]][🖼️galtzo-discord] [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]][🖼️ruby-lang] [![oauth2 Logo by Chris Messina, CC BY-SA 3.0][🖼️oauth2-i]][🖼️oauth2]
[🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
@@ -30,7 +59,7 @@ This is a RubyGem for implementing OAuth 2.0 clients (not servers) in Ruby appli
### Quick Examples
-
+
Convert the following `curl` command into a token request using this gem...
```shell
@@ -61,7 +90,7 @@ NOTE: `header` - The content type specified in the `curl` is already the default
-
+
+ Find this repo on federated forges (Coming soon!)
-| Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
-|-----------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
-| 🧪 [ruby-oauth/oauth2 on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
-| 🧊 [ruby-oauth/oauth2 on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
-| 🐙 [ruby-oauth/oauth2 on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
-| 🤼 [OAuth Ruby Google Group][⛳gg-discussions] | "Active" | ➖ | ➖ | ➖ | ➖ | [💚][⛳gg-discussions] |
-| 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |
+| Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
+|-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
+| 🧪 [ruby-oauth/oauth2 on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
+| 🧊 [ruby-oauth/oauth2 on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
+| 🐙 [ruby-oauth/oauth2 on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
+| 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |
@@ -239,7 +201,7 @@ If you use a gem version of a core Ruby library, it should work fine!
Available as part of the Tidelift Subscription.
-
+
Need enterprise-level guarantees?
The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
@@ -258,143 +220,6 @@ Alternatively:
-## 🚀 Release Documentation
-
-### Version 2.0.x
-
-
- 2.0.x CHANGELOG and README
-
-| Version | Release Date | CHANGELOG | README |
-|---------|--------------|---------------------------------------|---------------------------------|
-| 2.0.17 | 2025-09-15 | [v2.0.17 CHANGELOG][2.0.17-changelog] | [v2.0.17 README][2.0.17-readme] |
-| 2.0.16 | 2025-09-14 | [v2.0.16 CHANGELOG][2.0.16-changelog] | [v2.0.16 README][2.0.16-readme] |
-| 2.0.15 | 2025-09-08 | [v2.0.15 CHANGELOG][2.0.15-changelog] | [v2.0.15 README][2.0.15-readme] |
-| 2.0.14 | 2025-08-31 | [v2.0.14 CHANGELOG][2.0.14-changelog] | [v2.0.14 README][2.0.14-readme] |
-| 2.0.13 | 2025-08-30 | [v2.0.13 CHANGELOG][2.0.13-changelog] | [v2.0.13 README][2.0.13-readme] |
-| 2.0.12 | 2025-05-31 | [v2.0.12 CHANGELOG][2.0.12-changelog] | [v2.0.12 README][2.0.12-readme] |
-| 2.0.11 | 2025-05-23 | [v2.0.11 CHANGELOG][2.0.11-changelog] | [v2.0.11 README][2.0.11-readme] |
-| 2.0.10 | 2025-05-17 | [v2.0.10 CHANGELOG][2.0.10-changelog] | [v2.0.10 README][2.0.10-readme] |
-| 2.0.9 | 2022-09-16 | [v2.0.9 CHANGELOG][2.0.9-changelog] | [v2.0.9 README][2.0.9-readme] |
-| 2.0.8 | 2022-09-01 | [v2.0.8 CHANGELOG][2.0.8-changelog] | [v2.0.8 README][2.0.8-readme] |
-| 2.0.7 | 2022-08-22 | [v2.0.7 CHANGELOG][2.0.7-changelog] | [v2.0.7 README][2.0.7-readme] |
-| 2.0.6 | 2022-07-13 | [v2.0.6 CHANGELOG][2.0.6-changelog] | [v2.0.6 README][2.0.6-readme] |
-| 2.0.5 | 2022-07-07 | [v2.0.5 CHANGELOG][2.0.5-changelog] | [v2.0.5 README][2.0.5-readme] |
-| 2.0.4 | 2022-07-01 | [v2.0.4 CHANGELOG][2.0.4-changelog] | [v2.0.4 README][2.0.4-readme] |
-| 2.0.3 | 2022-06-28 | [v2.0.3 CHANGELOG][2.0.3-changelog] | [v2.0.3 README][2.0.3-readme] |
-| 2.0.2 | 2022-06-24 | [v2.0.2 CHANGELOG][2.0.2-changelog] | [v2.0.2 README][2.0.2-readme] |
-| 2.0.1 | 2022-06-22 | [v2.0.1 CHANGELOG][2.0.1-changelog] | [v2.0.1 README][2.0.1-readme] |
-| 2.0.0 | 2022-06-21 | [v2.0.0 CHANGELOG][2.0.0-changelog] | [v2.0.0 README][2.0.0-readme] |
-
-
-
-[2.0.17-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2017---2025-09-15
-[2.0.16-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2016---2025-09-14
-[2.0.15-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2015---2025-09-08
-[2.0.14-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2014---2025-08-31
-[2.0.13-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2013---2025-08-30
-[2.0.12-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2012---2025-05-31
-[2.0.11-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2011---2025-05-23
-[2.0.10-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2010---2025-05-17
-[2.0.9-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#209---2022-09-16
-[2.0.8-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#208---2022-09-01
-[2.0.7-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#207---2022-08-22
-[2.0.6-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#206---2022-07-13
-[2.0.5-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#205---2022-07-07
-[2.0.4-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#204---2022-07-01
-[2.0.3-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#203---2022-06-28
-[2.0.2-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#202---2022-06-24
-[2.0.1-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#201---2022-06-22
-[2.0.0-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#200---2022-06-21
-
-[2.0.17-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.17/README.md
-[2.0.16-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.16/README.md
-[2.0.15-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.15/README.md
-[2.0.14-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.14/README.md
-[2.0.13-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.13/README.md
-[2.0.12-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.12/README.md
-[2.0.11-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.11/README.md
-[2.0.10-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.10/README.md
-[2.0.9-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.9/README.md
-[2.0.8-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.8/README.md
-[2.0.7-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.7/README.md
-[2.0.6-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.6/README.md
-[2.0.5-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.5/README.md
-[2.0.4-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.4/README.md
-[2.0.3-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.3/README.md
-[2.0.2-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.2/README.md
-[2.0.1-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.1/README.md
-[2.0.0-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.0/README.md
-
-### Older Releases
-
-
- 1.4.x CHANGELOGs and READMEs
-
-| Version | Release Date | CHANGELOG | README |
-|---------|--------------|---------------------------------------|---------------------------------|
-| 1.4.11 | Sep 16, 2022 | [v1.4.11 CHANGELOG][1.4.11-changelog] | [v1.4.11 README][1.4.11-readme] |
-| 1.4.10 | Jul 1, 2022 | [v1.4.10 CHANGELOG][1.4.10-changelog] | [v1.4.10 README][1.4.10-readme] |
-| 1.4.9 | Feb 20, 2022 | [v1.4.9 CHANGELOG][1.4.9-changelog] | [v1.4.9 README][1.4.9-readme] |
-| 1.4.8 | Feb 18, 2022 | [v1.4.8 CHANGELOG][1.4.8-changelog] | [v1.4.8 README][1.4.8-readme] |
-| 1.4.7 | Mar 19, 2021 | [v1.4.7 CHANGELOG][1.4.7-changelog] | [v1.4.7 README][1.4.7-readme] |
-| 1.4.6 | Mar 19, 2021 | [v1.4.6 CHANGELOG][1.4.6-changelog] | [v1.4.6 README][1.4.6-readme] |
-| 1.4.5 | Mar 18, 2021 | [v1.4.5 CHANGELOG][1.4.5-changelog] | [v1.4.5 README][1.4.5-readme] |
-| 1.4.4 | Feb 12, 2020 | [v1.4.4 CHANGELOG][1.4.4-changelog] | [v1.4.4 README][1.4.4-readme] |
-| 1.4.3 | Jan 29, 2020 | [v1.4.3 CHANGELOG][1.4.3-changelog] | [v1.4.3 README][1.4.3-readme] |
-| 1.4.2 | Oct 1, 2019 | [v1.4.2 CHANGELOG][1.4.2-changelog] | [v1.4.2 README][1.4.2-readme] |
-| 1.4.1 | Oct 13, 2018 | [v1.4.1 CHANGELOG][1.4.1-changelog] | [v1.4.1 README][1.4.1-readme] |
-| 1.4.0 | Jun 9, 2017 | [v1.4.0 CHANGELOG][1.4.0-changelog] | [v1.4.0 README][1.4.0-readme] |
-
-
-[1.4.11-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#1411---2022-09-16
-[1.4.10-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#1410---2022-07-01
-[1.4.9-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#149---2022-02-20
-[1.4.8-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#148---2022-02-18
-[1.4.7-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#147---2021-03-19
-[1.4.6-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#146---2021-03-19
-[1.4.5-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#145---2021-03-18
-[1.4.4-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#144---2020-02-12
-[1.4.3-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#143---2020-01-29
-[1.4.2-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#142---2019-10-01
-[1.4.1-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#141---2018-10-13
-[1.4.0-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#140---2017-06-09
-
-[1.4.11-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.11/README.md
-[1.4.10-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.10/README.md
-[1.4.9-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.9/README.md
-[1.4.8-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.8/README.md
-[1.4.7-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.7/README.md
-[1.4.6-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.6/README.md
-[1.4.5-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.5/README.md
-[1.4.4-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.4/README.md
-[1.4.3-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.3/README.md
-[1.4.2-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.2/README.md
-[1.4.1-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.1/README.md
-[1.4.0-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.0/README.md
-
-
- 1.3.x Readmes
-
-| Version | Release Date | Readme |
-|---------|--------------|--------------------------------------------------------------|
-| 1.3.1 | Mar 3, 2017 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.3.1/README.md |
-| 1.3.0 | Dec 27, 2016 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.3.0/README.md |
-
-
-
-
- ≤= 1.2.x Readmes (2016 and before)
-
-| Version | Release Date | Readme |
-|---------|--------------|--------------------------------------------------------------|
-| 1.2.0 | Jun 30, 2016 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.2.0/README.md |
-| 1.1.0 | Jan 30, 2016 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.1.0/README.md |
-| 1.0.0 | May 23, 2014 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.0.0/README.md |
-| < 1.0.0 | Find here | https://gitlab.com/ruby-oauth/oauth2/-/tags |
-
-
-
## ✨ Installation
Install the gem and add to the application's Gemfile by executing:
@@ -411,14 +236,14 @@ gem install oauth2
### 🔒 Secure Installation
-
+
For Medium or High Security Installations
-This gem is cryptographically signed and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
+This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
[stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
by following the instructions below.
-Add my public key (if you haven’t already; will expire 2045-04-29) as a trusted certificate:
+Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
```console
gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
@@ -440,6 +265,8 @@ If you want to up your security game full-time:
bundle config set --global trust-policy MediumSecurity
```
+`MediumSecurity` instead of `HighSecurity` is necessary if not all the gems you use are signed.
+
NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.
@@ -477,7 +304,7 @@ Compatibility is further distinguished as "Best Effort Support" or "Incidental S
This gem will install on Ruby versions >= v2.2 for 2.x releases.
See `1-4-stable` branch for older rubies.
-
+
Ruby Version Compatibility Policy
If something doesn't work on one of these interpreters, it's a bug.
@@ -502,6 +330,7 @@ run and pass on that implementation. When something breaks on your
implementation, you will be responsible for providing patches in a timely
fashion. If critical issues for a particular implementation exist at the time
of a major release, support for that Ruby version may be dropped.
+
| | Ruby OAuth2 Version | Maintenance Branch | Targeted Support | Best Effort Support | Incidental Support |
@@ -638,7 +467,11 @@ These extensions work regardless of whether you used the global or discrete conf
There are a few hacks you may need in your class to support Ruby < 2.4.2 or < 2.6.
They are likely not needed if you are on a newer Ruby.
-See [response_spec.rb](https://github.com/ruby-oauth/oauth2/blob/main/spec/oauth2/response_spec.rb) if you need to study the hacks for older Rubies.
+Expand the examples below, or the [ruby-oauth/snaky_hash](https://gitlab.com/ruby-oauth/snaky_hash) gem,
+or [response_spec.rb](https://github.com/ruby-oauth/oauth2/blob/main/spec/oauth2/response_spec.rb), for more ideas, especially if you need to study the hacks for older Rubies.
+
+ "additional"
response.parsed.class.name # => Hash (just, regular old Hash)
```
-
+
Debugging & Logging
Set an environment variable as per usual (e.g. with [dotenv](https://github.com/bkeepers/dotenv)).
@@ -729,6 +562,7 @@ client = OAuth2::Client.new(
logger: Logger.new("example.log", "weekly"),
)
```
+
### OAuth2::Response
@@ -752,6 +586,7 @@ a hash of the values), or `from_kvform` (if you have an
`application/x-www-form-urlencoded` encoded string of the values).
Options (since v2.0.x unless noted):
+
- `expires_latency` (Integer | nil): Seconds to subtract from expires_in when computing #expired? to offset latency.
- `token_name` (String | Symbol | nil): When multiple token-like fields exist in responses, select the field name to use as the access token (since v2.0.10).
- `mode` (Symbol | Proc | Hash): Controls how the token is transmitted on requests made via this AccessToken instance.
@@ -762,6 +597,7 @@ Options (since v2.0.x unless noted):
- a `Hash` with verb symbols as keys, for example `{get: :query, post: :header, delete: :header}`.
Note: Verb-dependent mode supports providers like Instagram that require query mode for `GET` and header mode for `POST`/`DELETE`
+
- Verb-dependent mode via `Proc` was added in v2.0.15
- Verb-dependent mode via `Hash` was added in v2.0.16
@@ -780,6 +616,7 @@ Response instance will contain the `OAuth2::Error` instance.
### Authorization Grants
Note on OAuth 2.1 (draft):
+
- PKCE is required for all OAuth clients using the authorization code flow (especially public clients). Implement PKCE in your app when required by your provider. See RFC 7636 and RFC 8252.
- Redirect URIs must be compared using exact string matching by the Authorization Server.
- The Implicit grant (response_type=token) and the Resource Owner Password Credentials grant are omitted from OAuth 2.1; they remain here for OAuth 2.0 compatibility but should be avoided for new apps.
@@ -788,6 +625,7 @@ Note on OAuth 2.1 (draft):
- The definitions of public and confidential clients are simplified to refer only to whether the client has credentials.
References:
+
- OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
- Aaron Parecki: https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1
- FusionAuth: https://fusionauth.io/blog/2020/04/15/whats-new-in-oauth-2-1
@@ -804,6 +642,7 @@ use. They are available via the [`#auth_code`](https://gitlab.com/ruby-oauth/oau
[`#assertion`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/assertion.rb) methods respectively.
These aren't full examples, but demonstrative of the differences between usage for each strategy.
+
```ruby
auth_url = client.auth_code.authorize_url(redirect_uri: "http://localhost:8080/oauth/callback")
access = client.auth_code.get_token("code_value", redirect_uri: "http://localhost:8080/oauth/callback")
@@ -887,7 +726,7 @@ access = client.password.get_token("jdoe", "s3cret", scope: "read")
#### Examples
-
+
JHipster UAA (Spring Cloud) password grant example (legacy; avoid when possible)
```ruby
@@ -928,6 +767,7 @@ puts access.to_hash # full token response
```
Notes:
+
- Resource Owner Password Credentials (ROPC) is deprecated in OAuth 2.1 and discouraged. Prefer Authorization Code + PKCE.
- If your deployment strictly demands the X-XSRF-TOKEN header, first fetch it from an endpoint that sets the XSRF-TOKEN cookie (often "/" or a login page) and pass it to headers.
- For Basic auth, auth_scheme: :basic_auth handles the Authorization header; you do not need to base64-encode manually.
@@ -937,6 +777,7 @@ Notes:
### Instagram API (verb‑dependent token mode)
Providers like Instagram require the access token to be sent differently depending on the HTTP verb:
+
- GET requests: token must be in the query string (?access_token=...)
- POST/DELETE requests: token must be in the Authorization header (Bearer ...)
@@ -1001,6 +842,7 @@ me = long_lived.get("/me", params: {fields: "id,username"}).parsed
```
Tips:
+
- Avoid query‑string bearer tokens unless required by your provider. Instagram explicitly requires it for GET.
- If you need a custom rule, you can pass a Proc for mode, e.g. mode: ->(verb) { verb == :get ? :query : :header }.
@@ -1107,6 +949,7 @@ resp = access.get("/v1/protected")
```
Notes:
+
- Files must contain the appropriate PEMs. The private key may be encrypted; if so, pass a password to `OpenSSL::PKey::RSA.new(File.read(path), ENV["KEY_PASSWORD"])`.
- If your certificate and key are in a PKCS#12/PFX bundle, you can load them like:
- `p12 = OpenSSL::PKCS12.new(File.read("client.p12"), ENV["P12_PASSWORD"])`
@@ -1280,7 +1123,7 @@ and [Tidelift][🏙️entsup-tidelift].
### Open Collective for Individuals
-Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/kettle-rb#backer)]
+Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/ruby-oauth#backer)]
NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
@@ -1290,27 +1133,19 @@ No backers yet. Be the first!
### Open Collective for Organizations
-Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/kettle-rb#sponsor)]
+Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/ruby-oauth#sponsor)]
NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
No sponsors yet. Be the first!
-
-### Open Collective for Donors
-
-
-
-[kettle-readme-backers]: https://github.com/kettle-rb/kettle-dev/blob/main/exe/kettle-readme-backers
+[kettle-readme-backers]: https://github.com/ruby-oauth/oauth2/blob/main/exe/kettle-readme-backers
### Another way to support open-source
-> How wonderful it is that nobody need wait a single moment before starting to improve the world.
->—Anne Frank
-
-I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions — totaling 79 hours of FLOSS coding over just the past seven days, a pretty regular week for me. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈 cats).
+I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈 cats).
If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in `bundle fund`.
@@ -1318,7 +1153,7 @@ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed
**[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
-[![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon]
+[![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
## 🔐 Security
@@ -1397,12 +1232,11 @@ For example:
spec.add_dependency("oauth2", "~> 2.0")
```
-
+
📌 Is "Platform Support" part of the public API? More details inside.
SemVer should, IMO, but doesn't explicitly, say that dropping support for specific Platforms
-is a *breaking change* to an API.
-It is obvious to many, but not all, and since the spec is silent, the bike shedding is endless.
+is a *breaking change* to an API, and for that reason the bike shedding is endless.
To get a better understanding of how SemVer is intended to work over a project's lifetime,
read this article from the creator of SemVer:
@@ -1423,7 +1257,7 @@ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright
## 🤑 A request for help
Maintainers have teeth and need to pay their dentists.
-After getting laid off in an RIF in March and filled with many dozens of rejections,
-I'm now spending ~60+ hours a week building open source tools.
+After getting laid off in an RIF in March, and encountering difficulty finding a new one,
+I began spending most of my time building open source tools.
I'm hoping to be able to pay for my kids' health insurance this month,
so if you value the work I am doing, I need your support.
Please consider sponsoring me or the project.
@@ -1451,7 +1285,7 @@ To join the community or get help 👇️ Join the Discord.
To say "thanks!" ☝️ Join the Discord or 👇️ send money.
-[![Sponsor ruby-oauth/oauth2 on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay-img] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal-img]
+[![Sponsor ruby-oauth/oauth2 on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
### Please give the project a star ⭐ ♥.
@@ -1499,7 +1333,7 @@ Thanks for RTFM. ☺️
[✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
[⛳️gem-namespace]: https://github.com/ruby-oauth/oauth2
[⛳️namespace-img]: https://img.shields.io/badge/namespace-OAuth2-3C2D2D.svg?style=square&logo=ruby&logoColor=white
-[⛳️gem-name]: https://rubygems.org/gems/oauth2
+[⛳️gem-name]: https://bestgems.org/gems/oauth2
[⛳️name-img]: https://img.shields.io/badge/name-oauth2-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
[⛳️tag-img]: https://img.shields.io/github/tag/ruby-oauth/oauth2.svg
[⛳️tag]: http://github.com/ruby-oauth/oauth2/releases
@@ -1548,11 +1382,11 @@ Thanks for RTFM. ☺️
[📜gh-wiki]: https://github.com/ruby-oauth/oauth2/wiki
[📜gl-wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
[📜gh-wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
-[👽dl-rank]: https://rubygems.org/gems/oauth2
+[👽dl-rank]: https://bestgems.org/gems/oauth2
[👽dl-ranki]: https://img.shields.io/gem/rd/oauth2.svg
[👽oss-help]: https://www.codetriage.com/ruby-oauth/oauth2
[👽oss-helpi]: https://www.codetriage.com/ruby-oauth/oauth2/badges/users.svg
-[👽version]: https://rubygems.org/gems/oauth2
+[👽version]: https://bestgems.org/gems/oauth2
[👽versioni]: https://img.shields.io/gem/v/oauth2.svg
[🏀qlty-mnt]: https://qlty.sh/gh/ruby-oauth/projects/oauth2
[🏀qlty-mnti]: https://qlty.sh/gh/ruby-oauth/projects/oauth2/maintainability.svg
@@ -1642,8 +1476,8 @@ Thanks for RTFM. ☺️
[📌changelog]: CHANGELOG.md
[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
-[📌gitmoji]:https://gitmoji.dev
-[📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
+[📌gitmoji]: https://gitmoji.dev
+[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.526-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
[🔐security]: SECURITY.md
diff --git a/Rakefile b/Rakefile
index 9f4f39b6..acb40883 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# kettle-dev Rakefile v1.1.24 - 2025-09-17
+# kettle-dev Rakefile v1.1.49 - 2025-11-07
# Ruby 2.3 (Safe Navigation) or higher required
#
# MIT License (see License.txt)
diff --git a/gemfiles/modular/documentation.gemfile b/gemfiles/modular/documentation.gemfile
index 78533908..47f1a9d3 100644
--- a/gemfiles/modular/documentation.gemfile
+++ b/gemfiles/modular/documentation.gemfile
@@ -9,3 +9,4 @@ gem "yard-relative_markdown_links", "~> 0.5.0"
# Std Lib extractions
gem "rdoc", "~> 6.11"
+gem "yard-fence", "~> 0.4", require: false # Ruby >= 3.2
diff --git a/gemfiles/modular/erb/r2.3/default.gemfile b/gemfiles/modular/erb/r2.3/default.gemfile
index a38f952f..ca868e84 100644
--- a/gemfiles/modular/erb/r2.3/default.gemfile
+++ b/gemfiles/modular/erb/r2.3/default.gemfile
@@ -1,5 +1,5 @@
# The cake is a lie.
-# erb v2.2, the oldest release on RubyGems.org, was never compatible with Ruby 2.3.
+# erb v2.2, the oldest release, was never compatible with Ruby 2.3.
# In addition, erb does not follow SemVer, and old rubies get dropped in a patch.
# This means we have no choice but to use the erb that shipped with Ruby 2.3
# /opt/hostedtoolcache/Ruby/2.3.8/x64/lib/ruby/gems/2.3.0/gems/erb-2.2.2/lib/erb.rb:670:in `prepare_trim_mode': undefined method `match?' for "-":String (NoMethodError)
diff --git a/gemfiles/modular/optional.gemfile b/gemfiles/modular/optional.gemfile
index dae6a950..2eda51c6 100644
--- a/gemfiles/modular/optional.gemfile
+++ b/gemfiles/modular/optional.gemfile
@@ -1 +1,2 @@
# Optional dependencies are not depended on directly, but may be used if present.
+gem "addressable", ">= 2.8", "< 3" # ruby >= 2.2
diff --git a/gemfiles/modular/x_std_libs/r2.4/libs.gemfile b/gemfiles/modular/x_std_libs/r2.4/libs.gemfile
index 5a3c5b6c..c1bcbd8f 100644
--- a/gemfiles/modular/x_std_libs/r2.4/libs.gemfile
+++ b/gemfiles/modular/x_std_libs/r2.4/libs.gemfile
@@ -1,3 +1,3 @@
-eval_gemfile "../../erb/r2.4/v2.2.gemfile"
+eval_gemfile "../../erb/r2.6/v2.2.gemfile"
eval_gemfile "../../mutex_m/r2.4/v0.1.gemfile"
eval_gemfile "../../stringio/r2.4/v0.0.2.gemfile"
diff --git a/oauth2.gemspec b/oauth2.gemspec
index 0556ea5c..a1d34e52 100644
--- a/oauth2.gemspec
+++ b/oauth2.gemspec
@@ -43,7 +43,6 @@ Gem::Specification.new do |spec|
end
gl_homepage = "https://gitlab.com/ruby-oauth/#{spec.name}"
- gh_mirror = spec.homepage
spec.post_install_message = %{
---+++--- oauth2 v#{gem_version} ---+++---
@@ -73,9 +72,9 @@ Thanks, @pboling / @galtzo
}
spec.metadata["homepage_uri"] = "https://#{spec.name.tr("_", "-")}.galtzo.com/"
- spec.metadata["source_code_uri"] = "#{gh_mirror}/tree/v#{spec.version}"
- spec.metadata["changelog_uri"] = "#{gh_mirror}/blob/v#{spec.version}/CHANGELOG.md"
- spec.metadata["bug_tracker_uri"] = "#{gh_mirror}/issues"
+ spec.metadata["source_code_uri"] = "#{spec.homepage}/tree/v#{spec.version}"
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/v#{spec.version}/CHANGELOG.md"
+ spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
spec.metadata["documentation_uri"] = "https://www.rubydoc.info/gems/#{spec.name}/#{spec.version}"
spec.metadata["mailing_list_uri"] = "https://groups.google.com/g/oauth-ruby"
spec.metadata["funding_uri"] = "https://github.com/sponsors/pboling"
@@ -86,8 +85,7 @@ Thanks, @pboling / @galtzo
# Specify which files are part of the released package.
spec.files = Dir[
- # Executables and tasks
- "exe/*",
+ # Code / tasks / data (NOTE: exe/ is specified via spec.bindir and spec.executables below)
"lib/**/*.rb",
"lib/**/*.rake",
# Signatures
@@ -109,6 +107,7 @@ Thanks, @pboling / @galtzo
"REEK",
"RUBOCOP.md",
"SECURITY.md",
+ "THREAT_MODEL.md",
]
spec.rdoc_options += [
"--title",
@@ -136,7 +135,7 @@ Thanks, @pboling / @galtzo
spec.add_dependency("version_gem", "~> 1.1", ">= 1.1.9") # ruby >= 2.2.0
# NOTE: It is preferable to list development dependencies in the gemspec due to increased
- # visibility and discoverability on RubyGems.org.
+ # visibility and discoverability.
# However, development dependencies in gemspec will install on
# all versions of Ruby that will run in CI.
# This gem, and its gemspec runtime dependencies, will install on Ruby down to 2.2.0.
@@ -153,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", "~> 1.1") # ruby >= 2.3.0
# Security
spec.add_development_dependency("bundler-audit", "~> 0.9.2") # ruby >= 2.0.0
@@ -166,8 +165,7 @@ Thanks, @pboling / @galtzo
# 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") # ruby >= 2.3
- spec.add_development_dependency("rspec-pending_for", "~> 0.0", ">= 0.0.17") # ruby >= 2.3, used to skip specs on incompatible Rubies
+ spec.add_development_dependency("kettle-test", "~> 1.0", ">= 1.0.6") # ruby >= 2.3
# Releasing
spec.add_development_dependency("ruby-progressbar", "~> 1.13") # ruby >= 0
@@ -179,7 +177,7 @@ Thanks, @pboling / @galtzo
# spec.add_dependency("git", ">= 1.19.1") # ruby >= 2.3
# Development tasks
- # The cake is a lie. erb v2.2, the oldest release on RubyGems.org, was never compatible with Ruby 2.3.
+ # The cake is a lie. erb v2.2, the oldest release, was never compatible with Ruby 2.3.
# This means we have no choice but to use the erb that shipped with Ruby 2.3
# /opt/hostedtoolcache/Ruby/2.3.8/x64/lib/ruby/gems/2.3.0/gems/erb-2.2.2/lib/erb.rb:670:in `prepare_trim_mode': undefined method `match?' for "-":String (NoMethodError)
# spec.add_development_dependency("erb", ">= 2.2") # ruby >= 2.3.0, not SemVer, old rubies get dropped in a patch.
@@ -201,6 +199,6 @@ Thanks, @pboling / @galtzo
# In Ruby 3.5 (HEAD) the CGI library has been pared down, so we also need to depend on gem "cgi" for ruby@head
# This is done in the "head" appraisal.
# See: https://github.com/vcr/vcr/issues/1057
- spec.add_development_dependency("vcr", ">= 4") # 6.0 claims to support ruby >= 2.3, but fails on ruby 2.4
- spec.add_development_dependency("webmock", ">= 3") # Last version to support ruby >= 2.3
+ # spec.add_development_dependency("vcr", ">= 4") # 6.0 claims to support ruby >= 2.3, but fails on ruby 2.4
+ # spec.add_development_dependency("webmock", ">= 3") # Last version to support ruby >= 2.3
end
diff --git a/test_gfm.rb b/test_gfm.rb
deleted file mode 100644
index 75c1dc67..00000000
--- a/test_gfm.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env ruby
-require 'bundler/setup'
-require 'yard'
-require 'yard/templates/helpers/markup_helper'
-
-puts "Before loading .yard_gfm_support.rb:"
-YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown].each_with_index do |p, i|
- puts " [#{i}] #{p.inspect}"
-end
-
-require './.yard_gfm_support.rb'
-
-puts "\nAfter loading .yard_gfm_support.rb:"
-YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown].each_with_index do |p, i|
- puts " [#{i}] #{p.inspect}"
-end
-
-puts "\nTesting KramdownGfmDocument:"
-
-test_md = <<-MD
- # Test
-
- ```ruby
- puts "hello"
- ```
-MD
-
-doc = KramdownGfmDocument.new(test_md)
-html = doc.to_html
-puts html
-puts "\nDoes output contain ? #{html.include?('')}"
-puts "Does output contain ? #{html.include?('
Date: Fri, 7 Nov 2025 18:22:32 -0700
Subject: [PATCH 06/14] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20kettle-dev?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Gemfile.lock | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index 65ed6feb..e6e1832d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -99,7 +99,7 @@ GEM
json (2.16.0)
jwt (3.1.2)
base64
- kettle-dev (1.1.49)
+ kettle-dev (1.1.50)
kettle-soup-cover (1.0.10)
simplecov (~> 0.22)
simplecov-cobertura (~> 3.0)
From 46d75d104137846e0141625277b0f35d50d3f754 Mon Sep 17 00:00:00 2001
From: "Peter H. Boling"
Date: Fri, 7 Nov 2025 18:57:25 -0700
Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=8E=A8=20Template=20bootstrap=20by?=
=?UTF-8?q?=20kettle-dev-setup=20v1.1.50?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Appraisals | 1 -
CONTRIBUTING.md | 7 +++++--
Rakefile | 2 +-
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/Appraisals b/Appraisals
index e1a741b5..5cacc191 100644
--- a/Appraisals
+++ b/Appraisals
@@ -47,7 +47,6 @@ appraise "dep-heads" do
eval_gemfile "modular/runtime_heads.gemfile"
end
-
appraise "ruby-2-4" do
eval_gemfile "modular/faraday_v1.gemfile"
eval_gemfile "modular/hashie_v1.gemfile"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4cbdfb9b..fbc87e94 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -30,7 +30,7 @@ after running `bin/setup`. These include:
- gem_checksums
- kettle-changelog
- kettle-commit-msg
-- oauth2-setup
+- kettle-dev-setup
- kettle-dvcs
- kettle-pre-release
- kettle-readme-backers
@@ -68,7 +68,9 @@ GitHub API and CI helpers
Releasing and signing
- SKIP_GEM_SIGNING: If set, skip gem signing during build/release
- GEM_CERT_USER: Username for selecting your public cert in `certs/.pem` (defaults to $USER)
-- SOURCE_DATE_EPOCH: Reproducible build timestamp. `kettle-release` will set this automatically for the session.
+- SOURCE_DATE_EPOCH: Reproducible build timestamp.
+ - `kettle-release` will set this automatically for the session.
+ - Not needed on bundler >= 2.7.0, as reproducible builds have become the default.
Git hooks and commit message helpers (exe/kettle-commit-msg)
- GIT_HOOK_BRANCH_VALIDATE: Branch name validation mode (e.g., `jira`) or `false` to disable
@@ -168,6 +170,7 @@ NOTE: To build without signing the gem set `SKIP_GEM_SIGNING` to any value in th
1. Update version.rb to contain the correct version-to-be-released.
2. Run `bundle exec kettle-changelog`.
3. Run `bundle exec kettle-release`.
+4. Stay awake and monitor the release process for any errors, and answer any prompts.
#### Manual process
diff --git a/Rakefile b/Rakefile
index acb40883..786d1916 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# kettle-dev Rakefile v1.1.49 - 2025-11-07
+# kettle-dev Rakefile v1.1.50 - 2025-11-07
# Ruby 2.3 (Safe Navigation) or higher required
#
# MIT License (see License.txt)
From 6263de80bc38d10d05aa9e85590f32771eca6ce5 Mon Sep 17 00:00:00 2001
From: "Peter H. Boling"
Date: Fri, 7 Nov 2025 19:03:12 -0700
Subject: [PATCH 08/14] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20kettle-dev?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Gemfile.lock | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index e6e1832d..dbb04aaf 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -99,7 +99,7 @@ GEM
json (2.16.0)
jwt (3.1.2)
base64
- kettle-dev (1.1.50)
+ kettle-dev (1.1.51)
kettle-soup-cover (1.0.10)
simplecov (~> 0.22)
simplecov-cobertura (~> 3.0)
From 27164bbe95d928c40bd51d0c7f90f56c02b7c120 Mon Sep 17 00:00:00 2001
From: "Peter H. Boling"
Date: Fri, 7 Nov 2025 19:03:17 -0700
Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=8E=A8=20Template=20bootstrap=20by?=
=?UTF-8?q?=20kettle-dev-setup=20v1.1.51?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Rakefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Rakefile b/Rakefile
index 786d1916..631e8b13 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# kettle-dev Rakefile v1.1.50 - 2025-11-07
+# kettle-dev Rakefile v1.1.51 - 2025-11-07
# Ruby 2.3 (Safe Navigation) or higher required
#
# MIT License (see License.txt)
From c110574a27bfbd7a301fbdf5239e2f4d215ee107 Mon Sep 17 00:00:00 2001
From: "Peter H. Boling"
Date: Fri, 7 Nov 2025 19:12:51 -0700
Subject: [PATCH 10/14] =?UTF-8?q?=F0=9F=93=9D=20Update=20docs=20site?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/OAuth2.html | 8 +-
docs/OAuth2/AccessToken.html | 54 +-
docs/OAuth2/Authenticator.html | 8 +-
docs/OAuth2/Client.html | 52 +-
docs/OAuth2/Error.html | 6 +-
docs/OAuth2/FilteredAttributes.html | 10 +-
.../FilteredAttributes/ClassMethods.html | 4 +-
docs/OAuth2/Response.html | 14 +-
docs/OAuth2/Strategy.html | 4 +-
docs/OAuth2/Strategy/Assertion.html | 64 +-
docs/OAuth2/Strategy/AuthCode.html | 24 +-
docs/OAuth2/Strategy/Base.html | 4 +-
docs/OAuth2/Strategy/ClientCredentials.html | 4 +-
docs/OAuth2/Strategy/Implicit.html | 16 +-
docs/OAuth2/Strategy/Password.html | 16 +-
docs/OAuth2/Version.html | 4 +-
docs/_index.html | 85 +-
docs/file.CHANGELOG.html | 122 +-
docs/file.CODE_OF_CONDUCT.html | 110 +-
docs/file.CONTRIBUTING.html | 156 +-
docs/file.FUNDING.html | 29 +-
docs/file.IRP.html | 36 +-
docs/file.LICENSE.html | 4 +-
docs/file.OIDC.html | 257 +-
docs/file.README.html | 2142 ++++++++---------
docs/file.RUBOCOP.html | 23 +-
docs/file.SECURITY.html | 16 +-
docs/file.THREAT_MODEL.html | 34 +-
docs/file_list.html | 135 --
docs/index.html | 2142 ++++++++---------
docs/top-level-namespace.html | 4 +-
31 files changed, 2598 insertions(+), 2989 deletions(-)
diff --git a/docs/OAuth2.html b/docs/OAuth2.html
index 3ca5c041..11eebbb6 100644
--- a/docs/OAuth2.html
+++ b/docs/OAuth2.html
@@ -119,8 +119,8 @@
OAUTH_DEBUG =
-
When true, enables verbose HTTP logging via Faraday’s logger middleware.
-Controlled by the OAUTH_DEBUG environment variable. Any case-insensitive
+
When true, enables verbose HTTP logging via Faraday’s logger middleware.
+Controlled by the OAUTH_DEBUG environment variable. Any case-insensitive
value equal to “true” will enable debugging.
@@ -415,9 +415,9 @@
diff --git a/docs/OAuth2/AccessToken.html b/docs/OAuth2/AccessToken.html
index 7d07ab1e..4eb602c5 100644
--- a/docs/OAuth2/AccessToken.html
+++ b/docs/OAuth2/AccessToken.html
@@ -826,13 +826,13 @@
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
+
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.
@@ -987,9 +987,9 @@
Verb-dependent Hash mode
- —
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., :query, post: :header, delete: :header); or a callable that accepts a request-verb parameter
+ —
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.
@@ -1020,7 +1020,7 @@
Verb-dependent Hash mode
- —
the parameter name to use for transmission of the
+ —
the parameter name to use for transmission of the
Access Token value in :body or :query transmission mode
@@ -1036,7 +1036,7 @@
Verb-dependent Hash mode
- —
the name of the response parameter that identifies the access token
+ —
the name of the response parameter that identifies the access token
When nil one of TOKEN_KEY_LOOKUP will be used
@@ -1533,21 +1533,21 @@
Note:
-
The method will use the first found token key in the following order:
+
The method will use the first found token key in the following order:
‘access_token’, ‘id_token’, ‘token’ (or their symbolic versions)
Note:
-
If multiple token keys are present, a warning will be issued unless
+
If multiple token keys are present, a warning will be issued unless
OAuth2.config.silence_extra_tokens_warning is true
Note:
-
If no token keys are present, a warning will be issued unless
+
If no token keys are present, a warning will be issued unless
OAuth2.config.silence_no_tokens_warning is true
@@ -2746,28 +2746,28 @@
Note:
-
If the token passed to the request
-is an access token, the server MAY revoke the respective refresh
+
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
+
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
+
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.
@@ -3083,9 +3083,9 @@
diff --git a/docs/OAuth2/Authenticator.html b/docs/OAuth2/Authenticator.html
index 0cb01dbe..7e023866 100644
--- a/docs/OAuth2/Authenticator.html
+++ b/docs/OAuth2/Authenticator.html
@@ -108,7 +108,7 @@
Overview
Builds and applies client authentication to token and revoke requests.
-
Depending on the selected mode, credentials are applied as Basic Auth
+
Depending on the selected mode, credentials are applied as Basic Auth
headers, request body parameters, or only the client_id is sent (TLS).
@@ -788,7 +788,7 @@
Apply the request credentials used to authenticate to the Authorization Server
-
Depending on the configuration, this might be as request params or as an
+
Depending on the configuration, this might be as request params or as an
Authorization header.
User-provided params and header take precedence.
@@ -883,9 +883,9 @@
diff --git a/docs/OAuth2/Client.html b/docs/OAuth2/Client.html
index c50ad592..beff8225 100644
--- a/docs/OAuth2/Client.html
+++ b/docs/OAuth2/Client.html
@@ -1243,7 +1243,7 @@
The Assertion strategy
-
This allows for assertion-based authentication where an identity provider
+
This allows for assertion-based authentication where an identity provider
asserts the identity of the user or client application seeking access.
@@ -1487,7 +1487,7 @@
Note:
-
The extract_access_token parameter is deprecated and will be removed in oauth2 v3.
+
The extract_access_token parameter is deprecated and will be removed in oauth2 v3.
Use access_token_class on initialization instead.
@@ -1523,12 +1523,10 @@
Examples:
—
-
a Hash of params for the token endpoint
-
- - params can include a ‘headers’ key with a Hash of request headers
- - params can include a ‘parse’ key with the Symbol name of response parsing strategy (default: :automatic)
- - params can include a ‘snaky’ key to control snake_case conversion (default: false)
-
+
a Hash of params for the token endpoint
+* params can include a ‘headers’ key with a Hash of request headers
+* params can include a ‘parse’ key with the Symbol name of response parsing strategy (default: :automatic)
+* params can include a ‘snaky’ key to control snake_case conversion (default: false)
@@ -1616,7 +1614,7 @@
Examples:
—
-
the initialized AccessToken instance, or nil if token extraction fails
+
the initialized AccessToken instance, or nil if token extraction fails
and raise_errors is false
@@ -1839,14 +1837,14 @@
The redirect_uri parameters, if configured
-
The redirect_uri query parameter is OPTIONAL (though encouraged) when
-requesting authorization. If it is provided at authorization time it MUST
+
The redirect_uri query parameter is OPTIONAL (though encouraged) when
+requesting authorization. If it is provided at authorization time it MUST
also be provided with the token exchange request.
-
OAuth 2.1 note: Authorization Servers must compare redirect URIs using exact string matching.
+
OAuth 2.1 note: Authorization Servers must compare redirect URIs using exact string matching.
This client simply forwards the configured redirect_uri; the exact-match validation happens server-side.
-
Providing :redirect_uri to the OAuth2::Client instantiation will take
+
Providing :redirect_uri to the OAuth2::Client instantiation will take
care of managing this.
@@ -1929,7 +1927,7 @@
Makes a request relative to the specified site root.
-
Updated HTTP 1.1 specification (IETF RFC 7231) relaxed the original constraint (IETF RFC 2616),
+
Updated HTTP 1.1 specification (IETF RFC 7231) relaxed the original constraint (IETF RFC 2616),
allowing the use of relative URLs in Location headers.
@@ -2041,7 +2039,7 @@
- — whether to raise an OAuth2::Error on 400+ status
+ —
whether to raise an OAuth2::Error on 400+ status
code response for this request. Overrides the client instance setting.
@@ -2243,28 +2241,28 @@
Note:
-
If the token passed to the request
-is an access token, the server MAY revoke the respective refresh
+
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
+
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
+
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.
@@ -2656,9 +2654,9 @@
diff --git a/docs/OAuth2/Error.html b/docs/OAuth2/Error.html
index 2e23dff5..78c78b30 100644
--- a/docs/OAuth2/Error.html
+++ b/docs/OAuth2/Error.html
@@ -105,7 +105,7 @@
Overview
Represents an OAuth2 error condition.
-
Wraps details from an OAuth2::Response or Hash payload returned by an
+
Wraps details from an OAuth2::Response or Hash payload returned by an
authorization server, exposing error code and description per RFC 6749.
@@ -772,9 +772,9 @@
diff --git a/docs/OAuth2/FilteredAttributes.html b/docs/OAuth2/FilteredAttributes.html
index 93942485..55a0ab89 100644
--- a/docs/OAuth2/FilteredAttributes.html
+++ b/docs/OAuth2/FilteredAttributes.html
@@ -92,8 +92,8 @@
Overview
Mixin that redacts sensitive instance variables in #inspect output.
-
Classes include this module and declare which attributes should be filtered
-using filtered_attributes. Any instance variable name that includes one of
+
Classes include this module and declare which attributes should be filtered
+using filtered_attributes. Any instance variable name that includes one of
those attribute names will be shown as [FILTERED] in the object’s inspect.
@@ -202,7 +202,7 @@
-
This method returns an undefined value.
Hook invoked when the module is included. Extends the including class with
+
This method returns an undefined value.
Hook invoked when the module is included. Extends the including class with
class-level helpers.
@@ -335,9 +335,9 @@
diff --git a/docs/OAuth2/FilteredAttributes/ClassMethods.html b/docs/OAuth2/FilteredAttributes/ClassMethods.html
index fc2ad592..94807c82 100644
--- a/docs/OAuth2/FilteredAttributes/ClassMethods.html
+++ b/docs/OAuth2/FilteredAttributes/ClassMethods.html
@@ -280,9 +280,9 @@
diff --git a/docs/OAuth2/Response.html b/docs/OAuth2/Response.html
index f2f77289..0a0d9c6e 100644
--- a/docs/OAuth2/Response.html
+++ b/docs/OAuth2/Response.html
@@ -101,7 +101,7 @@
Overview
-
The Response class handles HTTP responses in the OAuth2 gem, providing methods
+
The Response class handles HTTP responses in the OAuth2 gem, providing methods
to access and parse response data in various formats.
@@ -1430,22 +1430,22 @@
Note:
-
The parser can be supplied as the +:parse+ option in the form of a Proc
-(or other Object responding to #call) or a Symbol. In the latter case,
+
The parser can be supplied as the +:parse+ option in the form of a Proc
+(or other Object responding to #call) or a Symbol. In the latter case,
the actual parser will be looked up in @@parsers by the supplied Symbol.
Note:
-
If no +:parse+ option is supplied, the lookup Symbol will be determined
+
Note:
-
If #parser is a Proc, it will be called with no arguments, just
+
@@ -1619,9 +1619,9 @@
diff --git a/docs/OAuth2/Strategy.html b/docs/OAuth2/Strategy.html
index a75d5e8d..33004cea 100644
--- a/docs/OAuth2/Strategy.html
+++ b/docs/OAuth2/Strategy.html
@@ -107,9 +107,9 @@
Defined Under Namespace
diff --git a/docs/OAuth2/Strategy/Assertion.html b/docs/OAuth2/Strategy/Assertion.html
index 8f3917bb..9b50b18f 100644
--- a/docs/OAuth2/Strategy/Assertion.html
+++ b/docs/OAuth2/Strategy/Assertion.html
@@ -105,25 +105,25 @@
Overview
The Client Assertion Strategy
-
Sample usage:
- client = OAuth2::Client.new(client_id, client_secret,
- :site => ‘http://localhost:8080’,
+
Sample usage:
+ client = OAuth2::Client.new(client_id, client_secret,
+ :site => ‘http://localhost:8080’,
:auth_scheme => :request_body)
-
claim_set = {
- :iss => “http://localhost:3001”,
- :aud => “http://localhost:8080/oauth2/token”,
- :sub => “me@example.com”,
- :exp => Time.now.utc.to_i + 3600,
+
claim_set = {
+ :iss => “http://localhost:3001”,
+ :aud => “http://localhost:8080/oauth2/token”,
+ :sub => “me@example.com”,
+ :exp => Time.now.utc.to_i + 3600,
}
-
encoding = {
- :algorithm => ‘HS256’,
- :key => ‘secret_key’,
+
encoding = {
+ :algorithm => ‘HS256’,
+ :key => ‘secret_key’,
}
-
access = client.assertion.get_token(claim_set, encoding)
- access.token # actual access_token string
+
access = client.assertion.get_token(claim_set, encoding)
+ access.token # actual access_token string
access.get(“/api/stuff”) # making api calls with access token in header
@@ -292,29 +292,29 @@
Retrieve an access token given the specified client.
-
For reading on JWT and claim keys:
- @see https://github.com/jwt/ruby-jwt
- @see https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
- @see https://datatracker.ietf.org/doc/html/rfc7523#section-3
+
For reading on JWT and claim keys:
+ @see https://github.com/jwt/ruby-jwt
+ @see https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
+ @see https://datatracker.ietf.org/doc/html/rfc7523#section-3
@see https://www.iana.org/assignments/jwt/jwt.xhtml
-
There are many possible claim keys, and applications may ask for their own custom keys.
-Some typically required ones:
- :iss (issuer)
- :aud (audience)
- :sub (subject) – formerly :prn https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token-06#appendix-F
+
There are many possible claim keys, and applications may ask for their own custom keys.
+Some typically required ones:
+ :iss (issuer)
+ :aud (audience)
+ :sub (subject) – formerly :prn https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token-06#appendix-F
:exp, (expiration time) – in seconds, e.g. Time.now.utc.to_i + 3600
-
Note that this method does not validate presence of those four claim keys indicated as required by RFC 7523.
+
Note that this method does not validate presence of those four claim keys indicated as required by RFC 7523.
There are endpoints that may not conform with this RFC, and this gem should still work for those use cases.
-
These two options are passed directly to JWT.encode. For supported encoding arguments:
- @see https://github.com/jwt/ruby-jwt#algorithms-and-usage
+
These two options are passed directly to JWT.encode. For supported encoding arguments:
+ @see https://github.com/jwt/ruby-jwt#algorithms-and-usage
@see https://datatracker.ietf.org/doc/html/rfc7518#section-3.1
-
The object type of :key may depend on the value of :algorithm. Sample arguments:
- get_token(claim_set, => ‘HS256’, :key => ‘secret_key’)
- get_token(claim_set, => ‘RS256’, :key => OpenSSL::PKCS12.new(File.read(‘my_key.p12’), ‘not_secret’))
+
The object type of :key may depend on the value of :algorithm. Sample arguments:
+ get_token(claim_set, {:algorithm => 'HS256', :key => 'secret_key'})
+ get_token(claim_set, {:algorithm => 'RS256', :key => OpenSSL::PKCS12.new(File.read('my_key.p12'), 'not_secret')})
@@ -382,7 +382,7 @@
—
- this will be merged with the token response to create the AccessToken object
+
this will be merged with the token response to create the AccessToken object
@see the access_token_opts argument to Client#get_token
@@ -437,7 +437,7 @@
- — the url parameter scope that may be required by some endpoints
+ —
the url parameter scope that may be required by some endpoints
@see https://datatracker.ietf.org/doc/html/rfc7521#section-4.1
@@ -481,9 +481,9 @@
diff --git a/docs/OAuth2/Strategy/AuthCode.html b/docs/OAuth2/Strategy/AuthCode.html
index 9cf98f7c..66f488e8 100644
--- a/docs/OAuth2/Strategy/AuthCode.html
+++ b/docs/OAuth2/Strategy/AuthCode.html
@@ -105,19 +105,15 @@ Overview
The Authorization Code Strategy
-
OAuth 2.1 notes:
-
- - PKCE is required for all OAuth clients using the authorization code flow (especially public clients).
-This library does not enforce PKCE generation/verification; implement PKCE in your application when required.
- - Redirect URIs must be compared using exact string matching by the Authorization Server.
-This client forwards redirect_uri but does not perform server-side validation.
-
+
OAuth 2.1 notes:
+- PKCE is required for all OAuth clients using the authorization code flow (especially public clients).
+ This library does not enforce PKCE generation/verification; implement PKCE in your application when required.
+- Redirect URIs must be compared using exact string matching by the Authorization Server.
+ This client forwards redirect_uri but does not perform server-side validation.
-
References:
-
- - OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
- - OAuth for native apps (RFC 8252) and PKCE (RFC 7636)
-
+
References:
+- OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
+- OAuth for native apps (RFC 8252) and PKCE (RFC 7636)
@@ -483,9 +479,9 @@
diff --git a/docs/OAuth2/Strategy/Base.html b/docs/OAuth2/Strategy/Base.html
index 4b7954d8..25d0e02c 100644
--- a/docs/OAuth2/Strategy/Base.html
+++ b/docs/OAuth2/Strategy/Base.html
@@ -195,9 +195,9 @@
diff --git a/docs/OAuth2/Strategy/ClientCredentials.html b/docs/OAuth2/Strategy/ClientCredentials.html
index 32ccd5ca..0ae17856 100644
--- a/docs/OAuth2/Strategy/ClientCredentials.html
+++ b/docs/OAuth2/Strategy/ClientCredentials.html
@@ -343,9 +343,9 @@
diff --git a/docs/OAuth2/Strategy/Implicit.html b/docs/OAuth2/Strategy/Implicit.html
index 8c336a7e..1c4f1a99 100644
--- a/docs/OAuth2/Strategy/Implicit.html
+++ b/docs/OAuth2/Strategy/Implicit.html
@@ -105,15 +105,13 @@ Overview
The Implicit Strategy
-
IMPORTANT (OAuth 2.1): The Implicit grant (response_type=token) is omitted from the OAuth 2.1 draft specification.
+
IMPORTANT (OAuth 2.1): The Implicit grant (response_type=token) is omitted from the OAuth 2.1 draft specification.
It remains here for backward compatibility with OAuth 2.0 providers. Prefer the Authorization Code flow with PKCE.
-
References:
-
- - OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
- - Why drop implicit: https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1
- - Background: https://fusionauth.io/learn/expert-advice/oauth/differences-between-oauth-2-oauth-2-1/
-
+
References:
+- OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
+- Why drop implicit: https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1
+- Background: https://fusionauth.io/learn/expert-advice/oauth/differences-between-oauth-2-oauth-2-1/
@@ -420,9 +418,9 @@
diff --git a/docs/OAuth2/Strategy/Password.html b/docs/OAuth2/Strategy/Password.html
index c063b0a7..040c2902 100644
--- a/docs/OAuth2/Strategy/Password.html
+++ b/docs/OAuth2/Strategy/Password.html
@@ -105,15 +105,13 @@ Overview
The Resource Owner Password Credentials Authorization Strategy
-
IMPORTANT (OAuth 2.1): The Resource Owner Password Credentials grant is omitted in OAuth 2.1.
+
IMPORTANT (OAuth 2.1): The Resource Owner Password Credentials grant is omitted in OAuth 2.1.
It remains here for backward compatibility with OAuth 2.0 providers. Prefer Authorization Code + PKCE.
-
References:
-
- - OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
- - Okta explainer: https://developer.okta.com/blog/2019/12/13/oauth-2-1-how-many-rfcs
- - FusionAuth blog: https://fusionauth.io/blog/2020/04/15/whats-new-in-oauth-2-1
-
+
References:
+- OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
+- Okta explainer: https://developer.okta.com/blog/2019/12/13/oauth-2-1-how-many-rfcs
+- FusionAuth blog: https://fusionauth.io/blog/2020/04/15/whats-new-in-oauth-2-1
@@ -374,9 +372,9 @@
diff --git a/docs/OAuth2/Version.html b/docs/OAuth2/Version.html
index 3959a0a5..cd15b2c4 100644
--- a/docs/OAuth2/Version.html
+++ b/docs/OAuth2/Version.html
@@ -111,9 +111,9 @@
diff --git a/docs/_index.html b/docs/_index.html
index cd86d203..1f2eec5b 100644
--- a/docs/_index.html
+++ b/docs/_index.html
@@ -93,87 +93,6 @@
File Listing
LICENSE
-
CITATION
-
-
-
oauth2-2.0.10.gem
-
-
-
oauth2-2.0.11.gem
-
-
-
oauth2-2.0.12.gem
-
-
-
oauth2-2.0.13.gem
-
-
-
oauth2-2.0.14.gem
-
-
-
oauth2-2.0.15.gem
-
-
-
oauth2-2.0.16.gem
-
-
-
oauth2-2.0.17.gem
-
-
-
oauth2-2.0.10.gem
-
-
-
oauth2-2.0.11.gem
-
-
-
oauth2-2.0.12.gem
-
-
-
oauth2-2.0.13.gem
-
-
-
oauth2-2.0.14.gem
-
-
-
oauth2-2.0.15.gem
-
-
-
oauth2-2.0.16.gem
-
-
-
oauth2-2.0.17.gem
-
-
-
REEK
-
-
-
access_token
-
-
-
authenticator
-
-
-
client
-
-
-
error
-
-
-
filtered_attributes
-
-
-
response
-
-
-
strategy
-
-
-
version
-
-
-
oauth2
-
-
@@ -396,9 +315,9 @@
Namespace Listing A-Z
diff --git a/docs/file.CHANGELOG.html b/docs/file.CHANGELOG.html
index 43671ea7..e953df4b 100644
--- a/docs/file.CHANGELOG.html
+++ b/docs/file.CHANGELOG.html
@@ -63,9 +63,9 @@
All notable changes to this project will be documented in this file.
-
The format is based on Keep a Changelog,
-and this project adheres to Semantic Versioning,
-and yes, platform and engine support are part of the public API.
+
The format is based on Keep a Changelog,
+and this project adheres to Semantic Versioning,
+and yes, platform and engine support are part of the public API.
Please file a bug if you notice a violation of semantic versioning.
@@ -97,7 +97,7 @@
Fixed
Security
-
+
2.0.17 - 2025-09-15
@@ -112,10 +112,10 @@ Added
-
-gh!682 - AccessToken: support Hash-based verb-dependent token transmission mode (e.g., :query, post: :header)
+gh!682 - AccessToken: support Hash-based verb-dependent token transmission mode (e.g., {get: :query, post: :header})
-
+
2.0.16 - 2025-09-14
@@ -157,7 +157,7 @@ Changed
gh!681 - Upgrade to kettle-dev v1.1.19
-
+
2.0.15 - 2025-09-08
@@ -202,7 +202,7 @@ Fixed
- point badge to the correct workflow for Ruby 2.3 (caboose.yml)
-
+
2.0.14 - 2025-08-31
@@ -246,7 +246,7 @@ Added
gh!664 - README: Add example for JHipster UAA (Spring Cloud) password grant, converted from Postman/Net::HTTP by @pboling
-
+
2.0.13 - 2025-08-30
@@ -291,7 +291,7 @@ Fixed
Security
-
+
2.0.12 - 2025-05-31
@@ -332,7 +332,7 @@ Fixed
- Documentation Typos by @pboling
-
+
2.0.11 - 2025-05-23
@@ -393,7 +393,7 @@ Fixed
- Incorrect documentation related to silencing warnings (@pboling)
-
+
2.0.10 - 2025-05-17
@@ -500,7 +500,7 @@ Fixed
gh!646 - Change require to require_relative (improve performance) (@Aboling0)
-
+
2.0.9 - 2022-09-16
@@ -521,7 +521,7 @@ Changed
- Complete migration to Gitlab, updating all links, and references in VCS-managed files (@pboling)
-
+
2.0.8 - 2022-09-01
@@ -544,7 +544,7 @@ Added
-
+
2.0.7 - 2022-08-22
@@ -572,7 +572,7 @@ Fixed
!625 - Fixes the printed version in the post install message (@hasghari)
-
+
2.0.6 - 2022-07-13
@@ -587,7 +587,7 @@ Fixed
!624 - Fixes a regression in v2.0.5, where an error would be raised in refresh_token flows due to (legitimate) lack of access_token (@pboling)
-
+
2.0.5 - 2022-07-07
@@ -617,7 +617,7 @@ Fixed
-
+
2.0.4 - 2022-07-01
@@ -632,7 +632,7 @@ Fixed
!618 - In some scenarios the snaky option default value was not applied (@pboling)
-
+
2.0.3 - 2022-06-28
@@ -658,7 +658,7 @@ Fixed
!615 - Fix support for requests with blocks, see Faraday::Connection#run_request (@pboling)
-
+
2.0.2 - 2022-06-24
@@ -677,7 +677,7 @@ Fixed
!607 - CHANGELOG correction, reference to OAuth2::ConnectionError (@zavan)
-
+
2.0.1 - 2022-06-22
@@ -692,7 +692,7 @@ Added
- Increased test coverage to 99% (@pboling)
-
+
2.0.0 - 2022-06-21
@@ -850,7 +850,7 @@ Removed
!590 - Dependency: Removed multi_json (@stanhu)
-
+
1.4.11 - 2022-09-16
@@ -860,7 +860,7 @@
- Complete migration to Gitlab, updating all links, and references in VCS-managed files (@pboling)
-
+
1.4.10 - 2022-07-01
@@ -869,7 +869,7 @@
- FIPS Compatibility !587 (@akostadinov)
-
+
1.4.9 - 2022-02-20
@@ -887,7 +887,7 @@
- Add Windows and MacOS to test matrix
-
+
1.4.8 - 2022-02-18
@@ -904,7 +904,7 @@
!543 - Support for more modern Open SSL libraries (@pboling)
-
+
1.4.7 - 2021-03-19
@@ -914,7 +914,7 @@
!541 - Backport fix to expires_at handling !533 to 1-4-stable branch. (@dobon)
-
+
1.4.6 - 2021-03-19
@@ -928,7 +928,7 @@
!538 - Remove reliance on globally included OAuth2 in tests, analogous to !539 on main branch (@anderscarling)
-
+
1.4.5 - 2021-03-18
@@ -944,7 +944,7 @@
!500 - Fix YARD documentation formatting (@olleolleolle)
-
+
1.4.4 - 2020-02-12
@@ -954,7 +954,7 @@
!408 - Fixed expires_at for formatted time (@Lomey)
-
+
1.4.3 - 2020-01-29
@@ -972,7 +972,7 @@
!433 - allow field names with square brackets and numbers in params (@asm256)
-
+
1.4.2 - 2019-10-01
-
+
1.4.1 - 2018-10-13
-
+
1.4.0 - 2017-06-09
@@ -1044,7 +1044,7 @@
Dependency: Upgrade Faraday to 0.12 (@sferik)
-
+
1.3.1 - 2017-03-03
@@ -1055,7 +1055,7 @@
Dependency: Upgrade Faraday to Faraday 0.11 (@mcfiredrill, @rhymes, @pschambacher)
-
+
1.3.0 - 2016-12-28
@@ -1071,7 +1071,7 @@
- Add support for Faraday 0.10 (@rhymes)
-
+
1.2.0 - 2016-07-01
@@ -1082,7 +1082,7 @@
- Use
raise rather than fail to throw exceptions (@sferik)
-
+
1.1.0 - 2016-01-30
@@ -1092,7 +1092,7 @@
- Add support for Rack 2, and bump various other dependencies (@sferik)
-
+
1.0.0 - 2014-07-09
@@ -1112,7 +1112,7 @@ Fixed
- Fix Base64.strict_encode64 incompatibility with Ruby 1.8.7.
-
+
0.5.0 - 2011-07-29
@@ -1135,7 +1135,7 @@ Changed
breaking web_server renamed to auth_code.
-
+
0.4.1 - 2011-04-20
-
+
0.4.0 - 2011-04-20
-
+
0.3.0 - 2011-04-08
-
+
0.2.0 - 2011-04-01
-
+
0.1.1 - 2011-01-12
-
+
0.1.0 - 2010-10-13
-
+
0.0.13 - 2010-08-17
-
+
0.0.12 - 2010-08-17
-
+
0.0.11 - 2010-08-17
-
+
0.0.10 - 2010-06-19
-
+
0.0.9 - 2010-06-18
-
+
0.0.8 - 2010-04-27
-
+
0.0.7 - 2010-04-27
-
+
0.0.6 - 2010-04-25
-
+
0.0.5 - 2010-04-23
-
+
0.0.4 - 2010-04-22
-
+
0.0.3 - 2010-04-22
-
+
0.0.2 - 2010-04-22
-
+
0.0.1 - 2010-04-22
diff --git a/docs/file.CODE_OF_CONDUCT.html b/docs/file.CODE_OF_CONDUCT.html
index 4e34bb2e..dbbd6d87 100644
--- a/docs/file.CODE_OF_CONDUCT.html
+++ b/docs/file.CODE_OF_CONDUCT.html
@@ -61,139 +61,139 @@
Our Pledge
-
We as members, contributors, and leaders pledge to make participation in our
-community a harassment-free experience for everyone, regardless of age, body
-size, visible or invisible disability, ethnicity, sex characteristics, gender
-identity and expression, level of experience, education, socio-economic status,
-nationality, personal appearance, race, caste, color, religion, or sexual
+
We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
-
We pledge to act and interact in ways that contribute to an open, welcoming,
+
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
Our Standards
-
Examples of behavior that contributes to a positive environment for our
+
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- - Accepting responsibility and apologizing to those affected by our mistakes,
+ - Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- - Focusing on what is best not just for us as individuals, but for the overall
+ - Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
- - The use of sexualized language or imagery, and sexual attention or advances of
+ - The use of sexualized language or imagery, and sexual attention or advances of
any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- - Publishing others’ private information, such as a physical or email address,
+ - Publishing others’ private information, such as a physical or email address,
without their explicit permission
- - Other conduct which could reasonably be considered inappropriate in a
+ - Other conduct which could reasonably be considered inappropriate in a
professional setting
Enforcement Responsibilities
-
Community leaders are responsible for clarifying and enforcing our standards of
-acceptable behavior and will take appropriate and fair corrective action in
-response to any behavior that they deem inappropriate, threatening, offensive,
+
Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
-
Community leaders have the right and responsibility to remove, edit, or reject
-comments, commits, code, wiki edits, issues, and other contributions that are
-not aligned to this Code of Conduct, and will communicate reasons for moderation
+
Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
Scope
-
This Code of Conduct applies within all community spaces, and also applies when
-an individual is officially representing the community in public spaces.
-Examples of representing our community include using an official email address,
-posting via an official social media account, or acting as an appointed
+
This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official email address,
+posting via an official social media account, or acting as an appointed
representative at an online or offline event.
Enforcement
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported to the community leaders responsible for enforcement at
-
.
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+
.
All complaints will be reviewed and investigated promptly and fairly.
-
All community leaders are obligated to respect the privacy and security of the
+
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
Enforcement Guidelines
-
Community leaders will follow these Community Impact Guidelines in determining
+
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
-
1. Correction
+
1. Correction
-
Community Impact: Use of inappropriate language or other behavior deemed
+
Community Impact: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
-
Consequence: A private, written warning from community leaders, providing
-clarity around the nature of the violation and an explanation of why the
+
Consequence: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
-
2. Warning
+
2. Warning
-
Community Impact: A violation through a single incident or series of
+
Community Impact: A violation through a single incident or series of
actions.
-
Consequence: A warning with consequences for continued behavior. No
-interaction with the people involved, including unsolicited interaction with
-those enforcing the Code of Conduct, for a specified period of time. This
-includes avoiding interactions in community spaces as well as external channels
-like social media. Violating these terms may lead to a temporary or permanent
+
Consequence: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
ban.
-
3. Temporary Ban
+
3. Temporary Ban
-
Community Impact: A serious violation of community standards, including
+
Community Impact: A serious violation of community standards, including
sustained inappropriate behavior.
-
Consequence: A temporary ban from any sort of interaction or public
-communication with the community for a specified period of time. No public or
-private interaction with the people involved, including unsolicited interaction
-with those enforcing the Code of Conduct, is allowed during this period.
+
Consequence: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
-
4. Permanent Ban
+
4. Permanent Ban
-
Community Impact: Demonstrating a pattern of violation of community
-standards, including sustained inappropriate behavior, harassment of an
+
Community Impact: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
-
Consequence: A permanent ban from any sort of public interaction within the
+
Consequence: A permanent ban from any sort of public interaction within the
community.
Attribution
-
This Code of Conduct is adapted from the Contributor Covenant,
-version 2.1, available at
+
This Code of Conduct is adapted from the Contributor Covenant,
+version 2.1, available at
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
-
Community Impact Guidelines were inspired by
+
Community Impact Guidelines were inspired by
Mozilla’s code of conduct enforcement ladder.
-
For answers to common questions about this code of conduct, see the FAQ at
-https://www.contributor-covenant.org/faq. Translations are available at
+
For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
diff --git a/docs/file.CONTRIBUTING.html b/docs/file.CONTRIBUTING.html
index 69803d2c..0a22870a 100644
--- a/docs/file.CONTRIBUTING.html
+++ b/docs/file.CONTRIBUTING.html
@@ -59,8 +59,8 @@
Contributing
-
Bug reports and pull requests are welcome on CodeBerg, GitLab, or GitHub.
-This project should be a safe, welcoming space for collaboration, so contributors agree to adhere to
+
Bug reports and pull requests are welcome on CodeBerg, GitLab, or GitHub.
+This project should be a safe, welcoming space for collaboration, so contributors agree to adhere to
the code of conduct.
To submit a patch, please fork the project, create a patch with tests, and send a pull request.
@@ -85,86 +85,72 @@
Help out!
Executables vs Rake tasks
-
Executables shipped by oauth2 can be used with or without generating the binstubs.
-They will work when oauth2 is installed globally (i.e., gem install oauth2) and do not require that oauth2 be in your bundle.
+
Executables shipped by dependencies, such as kettle-dev, and stone_checksums, are available
+after running bin/setup. These include:
+ - gem_checksums
- kettle-changelog
- kettle-commit-msg
- - oauth2-setup
+ - kettle-dev-setup
- kettle-dvcs
- kettle-pre-release
- kettle-readme-backers
- kettle-release
-
However, the rake tasks provided by oauth2 do require oauth2 to be added as a development dependency and loaded in your Rakefile.
-See the full list of rake tasks in head of Rakefile
+
There are many Rake tasks available as well. You can see them by running:
-
Gemfile
-
group :development do
- gem "oauth2", require: false
-end
-
-
-
Rakefile
-
# Rakefile
-require "oauth2"
-
+
shell
+bin/rake -T
+
Environment Variables for Local Development
Below are the primary environment variables recognized by stone_checksums (and its integrated tools). Unless otherwise noted, set boolean values to the string “true” to enable.
-
General/runtime
-
- - DEBUG: Enable extra internal logging for this library (default: false)
- - REQUIRE_BENCH: Enable
require_bench to profile requires (default: false)
- - CI: When set to true, adjusts default rake tasks toward CI behavior
-
-
-
Coverage (kettle-soup-cover / SimpleCov)
-
- - K_SOUP_COV_DO: Enable coverage collection (default: true in .envrc)
- - K_SOUP_COV_FORMATTERS: Comma-separated list of formatters (html, xml, rcov, lcov, json, tty)
- - K_SOUP_COV_MIN_LINE: Minimum line coverage threshold (integer, e.g., 100)
- - K_SOUP_COV_MIN_BRANCH: Minimum branch coverage threshold (integer, e.g., 100)
- - K_SOUP_COV_MIN_HARD: Fail the run if thresholds are not met (true/false)
- - K_SOUP_COV_MULTI_FORMATTERS: Enable multiple formatters at once (true/false)
- - K_SOUP_COV_OPEN_BIN: Path to browser opener for HTML (empty disables auto-open)
- - MAX_ROWS: Limit console output rows for simplecov-console (e.g., 1)
-Tip: When running a single spec file locally, you may want K_SOUP_COV_MIN_HARD=false to avoid failing thresholds for a partial run.
-
-
-
GitHub API and CI helpers
-
- - GITHUB_TOKEN or GH_TOKEN: Token used by
ci:act and release workflow checks to query GitHub Actions status at higher rate limits
-
-
-
Releasing and signing
-
- - SKIP_GEM_SIGNING: If set, skip gem signing during build/release
- - GEM_CERT_USER: Username for selecting your public cert in
certs/<USER>.pem (defaults to $USER)
- - SOURCE_DATE_EPOCH: Reproducible build timestamp.
kettle-release will set this automatically for the session.
-
-
-
Git hooks and commit message helpers (exe/kettle-commit-msg)
-
- - GIT_HOOK_BRANCH_VALIDATE: Branch name validation mode (e.g.,
jira) or false to disable
- - GIT_HOOK_FOOTER_APPEND: Append a footer to commit messages when goalie allows (true/false)
- - GIT_HOOK_FOOTER_SENTINEL: Required when footer append is enabled — a unique first-line sentinel to prevent duplicates
- - GIT_HOOK_FOOTER_APPEND_DEBUG: Extra debug output in the footer template (true/false)
-
+
General/runtime
+- DEBUG: Enable extra internal logging for this library (default: false)
+- REQUIRE_BENCH: Enable require_bench to profile requires (default: false)
+- CI: When set to true, adjusts default rake tasks toward CI behavior
+
+
Coverage (kettle-soup-cover / SimpleCov)
+- K_SOUP_COV_DO: Enable coverage collection (default: true in .envrc)
+- K_SOUP_COV_FORMATTERS: Comma-separated list of formatters (html, xml, rcov, lcov, json, tty)
+- K_SOUP_COV_MIN_LINE: Minimum line coverage threshold (integer, e.g., 100)
+- K_SOUP_COV_MIN_BRANCH: Minimum branch coverage threshold (integer, e.g., 100)
+- K_SOUP_COV_MIN_HARD: Fail the run if thresholds are not met (true/false)
+- K_SOUP_COV_MULTI_FORMATTERS: Enable multiple formatters at once (true/false)
+- K_SOUP_COV_OPEN_BIN: Path to browser opener for HTML (empty disables auto-open)
+- MAX_ROWS: Limit console output rows for simplecov-console (e.g., 1)
+ Tip: When running a single spec file locally, you may want K_SOUP_COV_MIN_HARD=false to avoid failing thresholds for a partial run.
+
+
GitHub API and CI helpers
+- GITHUB_TOKEN or GH_TOKEN: Token used by ci:act and release workflow checks to query GitHub Actions status at higher rate limits
+
+
Releasing and signing
+- SKIP_GEM_SIGNING: If set, skip gem signing during build/release
+- GEM_CERT_USER: Username for selecting your public cert in certs/<USER>.pem (defaults to $USER)
+- SOURCE_DATE_EPOCH: Reproducible build timestamp.
+ - kettle-release will set this automatically for the session.
+ - Not needed on bundler >= 2.7.0, as reproducible builds have become the default.
+
+
Git hooks and commit message helpers (exe/kettle-commit-msg)
+- GIT_HOOK_BRANCH_VALIDATE: Branch name validation mode (e.g., jira) or false to disable
+- GIT_HOOK_FOOTER_APPEND: Append a footer to commit messages when goalie allows (true/false)
+- GIT_HOOK_FOOTER_SENTINEL: Required when footer append is enabled — a unique first-line sentinel to prevent duplicates
+- GIT_HOOK_FOOTER_APPEND_DEBUG: Extra debug output in the footer template (true/false)
For a quick starting point, this repository’s .envrc shows sane defaults, and .env.local can override them locally.
Appraisals
-
From time to time the appraisal2 gemfiles in gemfiles/ will need to be updated.
+
From time to time the appraisal2 gemfiles in gemfiles/ will need to be updated.
They are created and updated with the commands:
-
bin/rake appraisal:update
-
+
console
+bin/rake appraisal:update
+
When adding an appraisal to CI, check the runner tool cache to see which runner to use.
@@ -174,38 +160,40 @@
The Reek List
To refresh the reek list:
-
bundle exec reek > REEK
-
+
console
+bundle exec reek > REEK
+
Run Tests
To run all tests
-
bundle exec rake test
-
+
console
+bundle exec rake test
+
Spec organization (required)
- - One spec file per class/module. For each class or module under
lib/, keep all of its unit tests in a single spec file under spec/ that mirrors the path and file name exactly: lib/oauth2/release_cli.rb -> spec/oauth2/release_cli_spec.rb.
- - Never add a second spec file for the same class/module. Examples of disallowed names:
*_more_spec.rb, *_extra_spec.rb, *_status_spec.rb, or any other suffix that still targets the same class. If you find yourself wanting a second file, merge those examples into the canonical spec file for that class/module.
+ - One spec file per class/module. For each class or module under
lib/, keep all of its unit tests in a single spec file under spec/ that mirrors the path and file name exactly: lib/oauth2/my_class.rb -> spec/oauth2/my_class_spec.rb.
- Exception: Integration specs that intentionally span multiple classes. Place these under
spec/integration/ (or a clearly named integration folder), and do not directly mirror a single class. Name them after the scenario, not a class.
- - Migration note: If a duplicate spec file exists, move all examples into the canonical file and delete the duplicate. Do not leave stubs or empty files behind.
Lint It
Run all the default tasks, which includes running the gradually autocorrecting linter, rubocop-gradual.
-
bundle exec rake
-
+
console
+bundle exec rake
+
Or just run the linter.
-
bundle exec rake rubocop_gradual:autocorrect
-
+
console
+bundle exec rake rubocop_gradual:autocorrect
+
-
For more detailed information about using RuboCop in this project, please see the RUBOCOP.md guide. This project uses rubocop_gradual instead of vanilla RuboCop, which requires specific commands for checking violations.
+
For more detailed information about using RuboCop in this project, please see the RUBOCOP.md guide. This project uses rubocop_gradual instead of vanilla RuboCop, which requires specific commands for checking violations.
Important: Do not add inline RuboCop disables
@@ -213,7 +201,7 @@
Important: Do not add inli
- Prefer configuration-based exclusions when a rule should not apply to certain paths or files (e.g., via
.rubocop.yml).
- - When a violation is temporary and you plan to fix it later, record it in
.rubocop_gradual.lock using the gradual workflow:
+ - When a violation is temporary, and you plan to fix it later, record it in
.rubocop_gradual.lock using the gradual workflow:
-
bundle exec rake rubocop_gradual:autocorrect (preferred)
@@ -239,10 +227,10 @@ For Maintainers
One-time, Per-maintainer, Setup
-IMPORTANT: To sign a build,
-a public key for signing gems will need to be picked up by the line in the
-gemspec defining the spec.cert_chain (check the relevant ENV variables there).
-All releases to RubyGems.org are signed releases.
+
IMPORTANT: To sign a build,
+a public key for signing gems will need to be picked up by the line in the
+gemspec defining the spec.cert_chain (check the relevant ENV variables there).
+All releases are signed releases.
See: RubyGems Security Guide
NOTE: To build without signing the gem set SKIP_GEM_SIGNING to any value in the environment.
@@ -252,9 +240,10 @@ To release a new version:
Automated process
- - Update version.rb to contian the correct version-to-be-released.
+ - Update version.rb to contain the correct version-to-be-released.
- Run
bundle exec kettle-changelog.
- Run
bundle exec kettle-release.
+ - Stay awake and monitor the release process for any errors, and answer any prompts.
Manual process
@@ -288,8 +277,8 @@ Manual process
- Run
bundle exec rake build
- - Run
bin/gem_checksums (more context 1, 2)
-to create SHA-256 and SHA-512 checksums. This functionality is provided by the stone_checksums
+ - Run
bin/gem_checksums (more context 1, 2)
+to create SHA-256 and SHA-512 checksums. This functionality is provided by the stone_checksums
gem.
- The script automatically commits but does not push the checksums
@@ -300,17 +289,16 @@ Manual process
sha256sum pkg/<gem name>-<version>.gem
- - 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
-
+ - 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 the gem host configured in the gemspec.
diff --git a/docs/file.FUNDING.html b/docs/file.FUNDING.html
index aab97aa9..3a6b386d 100644
--- a/docs/file.FUNDING.html
+++ b/docs/file.FUNDING.html
@@ -65,35 +65,30 @@

-

+

-
🤑 Request for Help
+
🤑 A request for help
-
Maintainers have teeth and need to pay their dentists.
-After getting laid off in an RIF in March and filled with many dozens of rejections,
-I’m now spending ~60+ hours a week building open source tools.
-I’m hoping to be able to pay for my kids’ health insurance this month,
-so if you value the work I am doing, I need your support.
+
Maintainers have teeth and need to pay their dentists.
+After getting laid off in an RIF in March, and encountering difficulty finding a new one,
+I began spending most of my time building open source tools.
+I’m hoping to be able to pay for my kids’ health insurance this month,
+so if you value the work I am doing, I need your support.
Please consider sponsoring me or the project.
To join the community or get help 👇️ Join the Discord.

-
To say “thanks for maintaining such a great tool” ☝️ Join the Discord or 👇️ send money.
+
To say “thanks!” ☝️ Join the Discord or 👇️ send money.
-
💌
💌
💌 
+
💌
💌
💌 
Another Way to Support Open Source Software
-
- How wonderful it is that nobody need wait a single moment before starting to improve the world.
-—Anne Frank
-
-
-
I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions — totaling 79 hours of FLOSS coding over just the past seven days, a pretty regular week for me. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈 cats).
+
I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈 cats).
If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in bundle fund.
@@ -104,9 +99,9 @@
Another Way to Support Open
diff --git a/docs/file.IRP.html b/docs/file.IRP.html
index b2fb8145..38d6f80d 100644
--- a/docs/file.IRP.html
+++ b/docs/file.IRP.html
@@ -180,13 +180,11 @@
Legal & regulatory
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
-
+
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
@@ -194,26 +192,20 @@ References
Appendix: Example checklist for an incident
-
diff --git a/docs/file.LICENSE.html b/docs/file.LICENSE.html
index db020c50..8befb1fa 100644
--- a/docs/file.LICENSE.html
+++ b/docs/file.LICENSE.html
@@ -60,9 +60,9 @@
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/docs/file.OIDC.html b/docs/file.OIDC.html
index 60f480af..2f34a113 100644
--- a/docs/file.OIDC.html
+++ b/docs/file.OIDC.html
@@ -80,176 +80,153 @@ Raw OIDC with ruby-oauth/oauth2
This document complements the inline documentation by focusing on OpenID Connect (OIDC) 1.0 usage patterns when using this gem as an OAuth 2.0 client library.
-Scope of this document
-
- - Audience: Developers building an OAuth 2.0/OIDC Relying Party (RP, aka client) in Ruby.
- - Non-goals: This gem does not implement an OIDC Provider (OP, aka Authorization Server); for OP/server see other projects (e.g., doorkeeper + oidc extensions).
- - Status: Informational documentation with links to normative specs. The gem intentionally remains protocol-agnostic beyond OAuth 2.0; OIDC specifics (like ID Token validation) must be handled by your application.
-
-
-Key concepts refresher
-
- - OAuth 2.0 delegates authorization; it does not define authentication of the end-user.
- - OIDC layers an identity layer on top of OAuth 2.0, introducing:
-
- - ID Token: a JWT carrying claims about the authenticated end-user and the authentication event.
- - Standardized scopes: openid (mandatory), profile, email, address, phone, offline_access, and others.
- - UserInfo endpoint: a protected resource for retrieving user profile claims.
- - Discovery and Dynamic Client Registration (optional for providers/clients that support them).
-
-
-
-
-What this gem provides for OIDC
-
- - All OAuth 2.0 client capabilities required for OIDC flows: building authorization requests, exchanging authorization codes, refreshing tokens, and making authenticated resource requests.
- - Transport and parsing conveniences (snaky hash, Faraday integration, error handling, etc.).
- - Optional client authentication schemes useful with OIDC deployments:
-
- - basic_auth (default)
- - request_body (legacy)
- - tls_client_auth (MTLS)
- - private_key_jwt (OIDC-compliant when configured per OP requirements)
-
-
-
-
-What you must add in your app for OIDC
-
- - ID Token validation: This gem surfaces id_token values but does not verify them. Your app should:
-1) Parse the JWT (header, payload, signature)
-2) Fetch the OP JSON Web Key Set (JWKS) from discovery (or configure statically)
-3) Select the correct key by kid (when present) and verify the signature and algorithm
-4) Validate standard claims (iss, aud, exp, iat, nbf, azp, nonce when used, at_hash/c_hash when applicable)
-5) Enforce expected client_id, issuer, and clock skew policies
- - Nonce handling for Authorization Code flow with OIDC: generate a cryptographically-random nonce, bind it to the user session before redirect, include it in authorize request, and verify it in the ID Token on return.
- - PKCE is best practice and often required by OPs: generate/verifier, send challenge in authorize, send verifier in token request.
- - Session/state management: continue to validate state to mitigate CSRF; use exact redirect_uri matching.
-
+Scope of this document
+- Audience: Developers building an OAuth 2.0/OIDC Relying Party (RP, aka client) in Ruby.
+- Non-goals: This gem does not implement an OIDC Provider (OP, aka Authorization Server); for OP/server see other projects (e.g., doorkeeper + oidc extensions).
+- Status: Informational documentation with links to normative specs. The gem intentionally remains protocol-agnostic beyond OAuth 2.0; OIDC specifics (like ID Token validation) must be handled by your application.
+
+Key concepts refresher
+- OAuth 2.0 delegates authorization; it does not define authentication of the end-user.
+- OIDC layers an identity layer on top of OAuth 2.0, introducing:
+ - ID Token: a JWT carrying claims about the authenticated end-user and the authentication event.
+ - Standardized scopes: openid (mandatory), profile, email, address, phone, offline_access, and others.
+ - UserInfo endpoint: a protected resource for retrieving user profile claims.
+ - Discovery and Dynamic Client Registration (optional for providers/clients that support them).
+
+What this gem provides for OIDC
+- All OAuth 2.0 client capabilities required for OIDC flows: building authorization requests, exchanging authorization codes, refreshing tokens, and making authenticated resource requests.
+- Transport and parsing conveniences (snaky hash, Faraday integration, error handling, etc.).
+- Optional client authentication schemes useful with OIDC deployments:
+ - basic_auth (default)
+ - request_body (legacy)
+ - tls_client_auth (MTLS)
+ - private_key_jwt (OIDC-compliant when configured per OP requirements)
+
+What you must add in your app for OIDC
+- ID Token validation: This gem surfaces id_token values but does not verify them. Your app should:
+ 1) Parse the JWT (header, payload, signature)
+ 2) Fetch the OP JSON Web Key Set (JWKS) from discovery (or configure statically)
+ 3) Select the correct key by kid (when present) and verify the signature and algorithm
+ 4) Validate standard claims (iss, aud, exp, iat, nbf, azp, nonce when used, at_hash/c_hash when applicable)
+ 5) Enforce expected client_id, issuer, and clock skew policies
+- Nonce handling for Authorization Code flow with OIDC: generate a cryptographically-random nonce, bind it to the user session before redirect, include it in authorize request, and verify it in the ID Token on return.
+- PKCE is best practice and often required by OPs: generate/verifier, send challenge in authorize, send verifier in token request.
+- Session/state management: continue to validate state to mitigate CSRF; use exact redirect_uri matching.
Minimal OIDC Authorization Code example
-require "oauth2"
-require "jwt" # jwt/ruby-jwt
-require "net/http"
-require "json"
-
-client = OAuth2::Client.new(
- ENV.fetch("OIDC_CLIENT_ID"),
- ENV.fetch("OIDC_CLIENT_SECRET"),
- site: ENV.fetch("OIDC_ISSUER"), # e.g. https://accounts.example.com
- authorize_url: "/authorize", # or discovered
- token_url: "/token", # or discovered
-)
-
-# Step 1: Redirect to OP for consent/auth
-state = SecureRandom.hex(16)
+```ruby
+require “oauth2”
+require “jwt” # jwt/ruby-jwt
+require “net/http”
+require “json”
+
+client = OAuth2::Client.new(
+ ENV.fetch(“OIDC_CLIENT_ID”),
+ ENV.fetch(“OIDC_CLIENT_SECRET”),
+ site: ENV.fetch(“OIDC_ISSUER”), # e.g. https://accounts.example.com
+ authorize_url: “/authorize”, # or discovered
+ token_url: “/token”, # or discovered
+)
+
+Step 1: Redirect to OP for consent/auth
+state = SecureRandom.hex(16)
nonce = SecureRandom.hex(16)
pkce_verifier = SecureRandom.urlsafe_base64(64)
-pkce_challenge = Base64.urlsafe_encode64(Digest::SHA256.digest(pkce_verifier)).delete("=")
+pkce_challenge = Base64.urlsafe_encode64(Digest::SHA256.digest(pkce_verifier)).delete(“=”)
-authz_url = client.auth_code.authorize_url(
- scope: "openid profile email",
+authz_url = client.auth_code.authorize_url(
+ scope: “openid profile email”,
state: state,
nonce: nonce,
code_challenge: pkce_challenge,
- code_challenge_method: "S256",
- redirect_uri: ENV.fetch("OIDC_REDIRECT_URI"),
+ code_challenge_method: “S256”,
+ redirect_uri: ENV.fetch(“OIDC_REDIRECT_URI”),
)
-# redirect_to authz_url
+# redirect_to authz_url
-# Step 2: Handle callback
-# params[:code], params[:state]
-raise "state mismatch" unless params[:state] == state
+Step 2: Handle callback
+# params[:code], params[:state]
+raise “state mismatch” unless params[:state] == state
-token = client.auth_code.get_token(
+token = client.auth_code.get_token(
params[:code],
- redirect_uri: ENV.fetch("OIDC_REDIRECT_URI"),
+ redirect_uri: ENV.fetch(“OIDC_REDIRECT_URI”),
code_verifier: pkce_verifier,
-)
+)
-# The token may include: access_token, id_token, refresh_token, etc.
-id_token = token.params["id_token"] || token.params[:id_token]
+The token may include: access_token, id_token, refresh_token, etc.
+id_token = token.params[“id_token”] || token.params[:id_token]
-# Step 3: Validate the ID Token (simplified – add your own checks!)
-# Discover keys (example using .well-known)
-issuer = ENV.fetch("OIDC_ISSUER")
-jwks_uri = JSON.parse(Net::HTTP.get(URI.join(issuer, "/.well-known/openid-configuration"))).
- fetch("jwks_uri")
+Step 3: Validate the ID Token (simplified – add your own checks!)
+# Discover keys (example using .well-known)
+issuer = ENV.fetch(“OIDC_ISSUER”)
+jwks_uri = JSON.parse(Net::HTTP.get(URI.join(issuer, “/.well-known/openid-configuration”))).
+ fetch(“jwks_uri”)
jwks = JSON.parse(Net::HTTP.get(URI(jwks_uri)))
-keys = jwks.fetch("keys")
+keys = jwks.fetch(“keys”)
-# Use ruby-jwt JWK loader
-jwk_set = JWT::JWK::Set.new(keys.map { |k| JWT::JWK.import(k) })
+Use ruby-jwt JWK loader
+jwk_set = JWT::JWK::Set.new(keys.map { |k| JWT::JWK.import(k) })
-decoded, headers = JWT.decode(
+decoded, headers = JWT.decode(
id_token,
nil,
true,
- algorithms: ["RS256", "ES256", "PS256"],
+ algorithms: [“RS256”, “ES256”, “PS256”],
jwks: jwk_set,
verify_iss: true,
iss: issuer,
verify_aud: true,
- aud: ENV.fetch("OIDC_CLIENT_ID"),
-)
-
-# Verify nonce
-raise "nonce mismatch" unless decoded["nonce"] == nonce
-
-# Optionally: call UserInfo
-userinfo = token.get("/userinfo").parsed
-
-
-Notes on discovery and registration
-
- - Discovery: Most OPs publish configuration at issuer/.well-known/openid-configuration (OIDC Discovery 1.0). From there, resolve authorization_endpoint, token_endpoint, jwks_uri, userinfo_endpoint, etc.
- - Dynamic Client Registration: Some OPs allow registering clients programmatically (OIDC Dynamic Client Registration 1.0). This gem does not implement registration; use a plain HTTP client or Faraday and store credentials securely.
-
-
-Common pitfalls and tips
-
- - Always request the openid scope when you expect an ID Token. Without it, the OP may behave as vanilla OAuth 2.0.
- - Validate ID Token signature and claims before trusting any identity data. Do not rely solely on the presence of an id_token field.
- - Prefer Authorization Code + PKCE. Avoid Implicit; it is discouraged in modern guidance and may be disabled by providers.
- - Use exact redirect_uri matching, and keep your allow-list short.
- - For public clients that use refresh tokens, prefer sender-constrained tokens (DPoP/MTLS) or rotation with one-time-use refresh tokens, per modern best practices.
- - When using private_key_jwt, ensure the “aud” (or token_url) and “iss/sub” claims are set per the OP’s rules, and include kid in the JWT header when required so the OP can select the right key.
-
-
-Relevant specifications and references
-
- - OpenID Connect Core 1.0: https://openid.net/specs/openid-connect-core-1_0.html
- - OIDC Core (final): https://openid.net/specs/openid-connect-core-1_0-final.html
- - How OIDC works: https://openid.net/developers/how-connect-works/
- - OpenID Connect home: https://openid.net/connect/
- - OIDC Discovery 1.0: https://openid.net/specs/openid-connect-discovery-1_0.html
- - OIDC Dynamic Client Registration 1.0: https://openid.net/specs/openid-connect-registration-1_0.html
- - OIDC Session Management 1.0: https://openid.net/specs/openid-connect-session-1_0.html
- - OIDC RP-Initiated Logout 1.0: https://openid.net/specs/openid-connect-rpinitiated-1_0.html
- - OIDC Back-Channel Logout 1.0: https://openid.net/specs/openid-connect-backchannel-1_0.html
- - OIDC Front-Channel Logout 1.0: https://openid.net/specs/openid-connect-frontchannel-1_0.html
- - Auth0 OIDC overview: https://auth0.com/docs/authenticate/protocols/openid-connect-protocol
- - Spring Authorization Server’s list of OAuth2/OIDC specs: https://github.com/spring-projects/spring-authorization-server/wiki/OAuth2-and-OIDC-Specifications
-
-
-See also
-
- - README sections on OAuth 2.1 notes and OIDC notes
- - Strategy classes under lib/oauth2/strategy for flow helpers
- - Specs under spec/oauth2 for concrete usage patterns
-
-
-Contributions welcome
-
- - If you discover provider-specific nuances, consider contributing examples or clarifications (without embedding provider-specific hacks into the library).
-
+ aud: ENV.fetch(“OIDC_CLIENT_ID”),
+)