oauth2 2.0.20 → 2.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,17 +1,10 @@
1
- [![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]
1
+ <a href="https://github.com/ruby-oauth"><img alt="ruby-oauth Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/ruby-oauth/avatar-128px.svg" width="14%" align="right"/></a>
2
2
 
3
- [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
4
- [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
5
- [🖼️ruby-lang-i]: https://logos.galtzo.com/assets/images/ruby-lang/avatar-192px.svg
6
- [🖼️ruby-lang]: https://www.ruby-lang.org/
7
- [🖼️oauth2-i]: https://logos.galtzo.com/assets/images/oauth/oauth2/avatar-192px.svg
8
- [🖼️oauth2]: https://github.com/ruby-oauth/oauth2
3
+ # 🔐 OAuth2
9
4
 
10
- # 🔐 OAuth 2.0 Authorization Framework
5
+ [![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
11
6
 
12
- [![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Legacy][🚎4-lg-wfi]][🚎4-lg-wf] [![CI Unsupported][🚎7-us-wfi]][🚎7-us-wf] [![CI Ancient][🚎1-an-wfi]][🚎1-an-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
13
-
14
- `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
7
+ `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][✉️discord-invite], as I may have missed the [discord notification][✉️discord-invite].
15
8
 
16
9
  ---
17
10
 
@@ -20,13 +13,13 @@
20
13
  [![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 at ko-fi.com][🖇kofi-img]][🖇kofi]
21
14
 
22
15
  <details>
23
- <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
16
+ <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
24
17
 
25
18
  I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).
26
19
 
27
20
  </details>
28
21
 
29
- ## 🌻 Synopsis
22
+ ## 🌻 Synopsis <a href="https://discord.gg/3qme4XHNKN"><img alt="Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px.svg" width="8%" align="right"/></a> <a href="https://ruby-toolbox.com"><img alt="ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5" src="https://logos.galtzo.com/assets/images/ruby-lang/avatar-128px.svg" width="8%" align="right"/></a>
30
23
 
31
24
  OAuth 2.0 is the industry-standard protocol for authorization.
32
25
  This is a RubyGem for implementing OAuth 2.0 clients (not servers) in Ruby applications.
@@ -56,7 +49,7 @@ client = OAuth2::Client.new(
56
49
  "REDMOND_CLIENT_SECRET", # client_secret
57
50
  auth_scheme: :request_body, # Other modes are supported: :basic_auth, :tls_client_auth, :private_key_jwt
58
51
  token_url: "oauth2/token", # relative path, except with leading `/`, then absolute path
59
- site: "https://login.microsoftonline.com/REDMOND_REDACTED",
52
+ site: "https://login.microsoftonline.com/REDMOND_REDACTED"
60
53
  )
61
54
  client.
62
55
  client_credentials. # There are many other types to choose from!
@@ -124,51 +117,88 @@ Notes
124
117
 
125
118
  </details>
126
119
 
127
- If it seems like you are in the wrong place, you might try one of these:
120
+ ### Alternatives
121
+
122
+ This gem is a low-level OAuth 2.0 **client** (it talks _to_ an authorization server to obtain and use tokens).
123
+ If that isn't quite what you need, one of the following libraries may be a better fit (the first row is this gem for comparison):
128
124
 
129
- * [OAuth 2.0 Spec][oauth2-spec]
130
- * [doorkeeper gem][doorkeeper-gem] for OAuth 2.0 server/provider implementation.
131
- * [oauth sibling gem][sibling-gem] for OAuth 1.0a implementations in Ruby.
125
+ | Library | Role | When to use it |
126
+ |-------------------------------------------------------------------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
127
+ | **this gem** ([oauth2][📜src-gh]) | OAuth 2.0 / 2.1 + OIDC **client** | You are calling an OAuth 2.0 API, or signing in against a provider, and want a small, dependency-light, spec-faithful client with fine-grained control over the request/response cycle. |
128
+ | [oauth2-mcp][sibling-mcp-gem] | OAuth 2.1 MCP Auth client **and** server | Focused, spec-faithful, MCP Auth client with fine-grained control over the request/response cycle. Rack/Roda compatible clients and servers. Built on top of this gem, [oauth2][📜src-gh]. |
129
+ | [omniauth][omniauth-gem] + [omniauth-oauth2][omniauth-oauth2-gem] | "Log in with…" **client** (Rack) | You primarily want user _authentication_ ("Log in with GitHub/GitLab/Google") wired into a Rack/Rails app via a strategy, rather than driving the token flow yourself. Built on top of this gem, [oauth2][📜src-gh]. |
130
+ | [openid_connect][openid-connect-gem] | OpenID Connect client & server | You need full [OpenID Connect][oidc-spec] (ID-token validation, discovery, userinfo, etc.) with batteries included. Maintained by [@nov][nov]. |
131
+ | [rack-oauth2][rack-oauth2-gem] | OAuth 2.0 client **and** server | You want lower-level Rack primitives, need both client and server pieces, or are building on top of `openid_connect`. Maintained by [@nov][nov]. |
132
+ | [doorkeeper][doorkeeper-gem] | OAuth 2.0 **server / provider** | You want to _be_ the authorization server — issuing tokens to other apps — in a Rails/Grape/Sinatra application, rather than acting as a client. |
133
+ | [oauth][sibling-gem] | OAuth **1.0a** client & server | The provider you integrate with only speaks the older OAuth 1.0a protocol. This is our sibling gem. |
134
+
135
+ See also the [OAuth 2.0 Spec][oauth2-spec], the [OpenID Connect Spec][oidc-spec], and the [MCP Auth Spec][mcp-auth-spec].
132
136
 
133
137
  [oauth2-spec]: https://oauth.net/2/
138
+ [oidc-spec]: https://openid.net/specs/openid-connect-core-1_0.html
139
+ [mcp-auth-spec]: https://modelcontextprotocol.io/specification/draft/basic/authorization
134
140
  [sibling-gem]: https://gitlab.com/ruby-oauth/oauth
141
+ [sibling-mcp-gem]: https://github.com/ruby-oauth/oauth2-mcp
135
142
  [doorkeeper-gem]: https://github.com/doorkeeper-gem/doorkeeper
143
+ [omniauth-gem]: https://github.com/omniauth/omniauth
144
+ [omniauth-oauth2-gem]: https://github.com/omniauth/omniauth-oauth2
145
+ [openid-connect-gem]: https://github.com/nov/openid_connect
146
+ [rack-oauth2-gem]: https://github.com/nov/rack-oauth2
147
+ [nov]: https://github.com/nov
136
148
 
137
149
  ## 💡 Info you can shake a stick at
138
150
 
139
- | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
151
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
140
152
  |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
141
- | Works with JRuby | ![JRuby 9.1 Compat][💎jruby-9.1i] ![JRuby 9.2 Compat][💎jruby-9.2i] ![JRuby 9.3 Compat][💎jruby-9.3i] <br/> [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎10-j-wf] [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
142
- | Works with Truffle Ruby | ![Truffle Ruby 22.3 Compat][💎truby-22.3i] ![Truffle Ruby 23.0 Compat][💎truby-23.0i] ![Truffle Ruby 23.1 Compat][💎truby-23.1i] <br/> [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
143
- | Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎4-lg-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎6-s-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] |
144
- | Works with MRI Ruby 2 | ![Ruby 2.2 Compat][💎ruby-2.2i] <br/> [![Ruby 2.3 Compat][💎ruby-2.3i]][🚎1-an-wf] [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎1-an-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎1-an-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎7-us-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎7-us-wf] |
145
- | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
146
- | Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
147
- | Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
148
- | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
149
- | Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |
150
- | Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |
151
- | `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
153
+ | Works with JRuby | [![JRuby 9.2 Compat][💎jruby-9.2i]][🚎jruby-9.2-wf] [![JRuby 9.3 Compat][💎jruby-9.3i]][🚎jruby-9.3-wf] <br/> [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎jruby-9.4-wf] [![JRuby current Compat][💎jruby-c-i]][🚎10-j-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf]|
154
+ | Works with Truffle Ruby | [![Truffle Ruby 22.3 Compat][💎truby-22.3i]][🚎truby-22.3-wf] [![Truffle Ruby 23.0 Compat][💎truby-23.0i]][🚎truby-23.0-wf] [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎truby-23.1-wf] <br/> [![Truffle Ruby 24.2 Compat][💎truby-24.2i]][🚎truby-24.2-wf] [![Truffle Ruby 25.0 Compat][💎truby-25.0i]][🚎truby-25.0-wf] [![Truffle Ruby current Compat][💎truby-c-i]][🚎9-t-wf]|
155
+ | Works with MRI Ruby 4 | [![Ruby 4.0 Compat][💎ruby-4.0i]][🚎11-c-wf] [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf]|
156
+ | Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎ruby-3.0-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎ruby-3.1-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎ruby-3.2-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎ruby-3.3-wf] [![Ruby 3.4 Compat][💎ruby-3.4i]][🚎ruby-3.4-wf]|
157
+ | Works with MRI Ruby 2 | ![Ruby 2.2 Compat][💎ruby-2.2i] ![Ruby 2.3 Compat][💎ruby-2.3i] <br/> [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎ruby-2.4-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎ruby-2.5-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎ruby-2.6-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎ruby-2.7-wf]|
158
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
159
+ | Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
160
+ | Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
161
+ | Compliance | [![License: MIT][📄license-img]][📄license] [![Apache license compatibility: Category A][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
162
+ | Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |
163
+ | Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |
164
+ | `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
152
165
 
153
166
  ### Compatibility
154
167
 
155
168
  Compatible with MRI Ruby 2.2.0+, and concordant releases of JRuby, and TruffleRuby.
169
+ CI workflows and Appraisals are generated for MRI Ruby 2.4+.
170
+ This test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml` and
171
+ may be higher than the gem's runtime compatibility floor when legacy Rubies are
172
+ not practical for the current toolchain.
173
+
174
+ | 🚚 _Amazing_ test matrix was brought to you by | The Kettle dev/test stack |
175
+ |------------------------------------------------|---------------------------|
156
176
 
157
- | 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
158
- |------------------------------------------------|--------------------------------------------------------|
159
- | 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
177
+ <details>
178
+ <summary>How We Manage Complexity In Tests</summary>
179
+
180
+ | Gem | Source | Role | Daily download rank |
181
+ |-----|--------|------|---------------------|
182
+ | [appraisal2](https://bestgems.org/gems/appraisal2) | [GitHub](https://github.com/appraisal-rb/appraisal2) | multi-dependency Appraisal matrix generation | [![Daily download rank for appraisal2](https://img.shields.io/gem/rd/appraisal2.svg?style=flat-square)](https://bestgems.org/gems/appraisal2) |
183
+ | [appraisal2-rubocop](https://bestgems.org/gems/appraisal2-rubocop) | [GitHub](https://github.com/appraisal-rb/appraisal2-rubocop) | RuboCop Appraisal generator integration | [![Daily download rank for appraisal2-rubocop](https://img.shields.io/gem/rd/appraisal2-rubocop.svg?style=flat-square)](https://bestgems.org/gems/appraisal2-rubocop) |
184
+ | [turbo_tests2](https://bestgems.org/gems/turbo_tests2) | [GitHub](https://github.com/galtzo-floss/turbo_tests2) | parallel test execution | [![Daily download rank for turbo_tests2](https://img.shields.io/gem/rd/turbo_tests2.svg?style=flat-square)](https://bestgems.org/gems/turbo_tests2) |
185
+ | [kettle-test](https://bestgems.org/gems/kettle-test) | [GitHub](https://github.com/kettle-dev/kettle-test) | standard test runner and coverage harness | [![Daily download rank for kettle-test](https://img.shields.io/gem/rd/kettle-test.svg?style=flat-square)](https://bestgems.org/gems/kettle-test) |
186
+ | [kettle-soup-cover](https://bestgems.org/gems/kettle-soup-cover) | [GitHub](https://github.com/kettle-dev/kettle-soup-cover) | SimpleCov coverage policy and reporting | [![Daily download rank for kettle-soup-cover](https://img.shields.io/gem/rd/kettle-soup-cover.svg?style=flat-square)](https://bestgems.org/gems/kettle-soup-cover) |
187
+ | [rubocop-lts](https://bestgems.org/gems/rubocop-lts) | [GitHub](https://github.com/rubocop-lts/rubocop-lts) | Ruby-version-aware linting | [![Daily download rank for rubocop-lts](https://img.shields.io/gem/rd/rubocop-lts.svg?style=flat-square)](https://bestgems.org/gems/rubocop-lts) |
188
+
189
+ </details>
160
190
 
161
191
  ### Federated DVCS
162
192
 
163
193
  <details markdown="1">
164
- <summary>Find this repo on federated forges (Coming soon!)</summary>
194
+ <summary>Find this repo on federated forges (Coming soon!)</summary>
165
195
 
166
- | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
196
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
167
197
  |-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
168
- | 🧪 [ruby-oauth/oauth2 on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
169
- | 🧊 [ruby-oauth/oauth2 on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
170
- | 🐙 [ruby-oauth/oauth2 on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
171
- | 🎮️ [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] |
198
+ | 🧪 [ruby-oauth/oauth2 on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
199
+ | 🧊 [ruby-oauth/oauth2 on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
200
+ | 🐙 [ruby-oauth/oauth2 on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
201
+ | 🎮️ [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] |
172
202
 
173
203
  </details>
174
204
 
@@ -179,7 +209,7 @@ Compatible with MRI Ruby 2.2.0+, and concordant releases of JRuby, and TruffleRu
179
209
  Available as part of the Tidelift Subscription.
180
210
 
181
211
  <details markdown="1">
182
- <summary>Need enterprise-level guarantees?</summary>
212
+ <summary>Need enterprise-level guarantees?</summary>
183
213
 
184
214
  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.
185
215
 
@@ -211,114 +241,6 @@ If bundler is not being used to manage dependencies, install the gem by executin
211
241
  gem install oauth2
212
242
  ```
213
243
 
214
- ### 🔒 Secure Installation
215
-
216
- <details markdown="1">
217
- <summary>For Medium or High Security Installations</summary>
218
-
219
- This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
220
- [stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
221
- by following the instructions below.
222
-
223
- Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
224
-
225
- ```console
226
- gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
227
- ```
228
-
229
- You only need to do that once. Then proceed to install with:
230
-
231
- ```console
232
- gem install oauth2 -P MediumSecurity
233
- ```
234
-
235
- The `MediumSecurity` trust profile will verify signed gems, but allow the installation of unsigned dependencies.
236
-
237
- This is necessary because not all of `oauth2`’s dependencies are signed, so we cannot use `HighSecurity`.
238
-
239
- If you want to up your security game full-time:
240
-
241
- ```console
242
- bundle config set --global trust-policy MediumSecurity
243
- ```
244
-
245
- `MediumSecurity` instead of `HighSecurity` is necessary if not all the gems you use are signed.
246
-
247
- NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.
248
-
249
- </details>
250
-
251
- ## What is new for v2.0?
252
-
253
- - Works with Ruby versions >= 2.2
254
- - Drop support for the expired MAC Draft (all versions)
255
- - Support IETF rfc7515 JSON Web Signature - JWS (since v2.0.12)
256
- - Support JWT `kid` for key discovery and management
257
- - Support IETF rfc7523 JWT Bearer Tokens (since v2.0.0)
258
- - Support IETF rfc7231 Relative Location in Redirect (since v2.0.0)
259
- - Support IETF rfc6749 Don't set oauth params when nil (since v2.0.0)
260
- - Support IETF rfc7009 Token Revocation (since v2.0.10, updated in v2.0.13 to support revocation via URL-encoded parameters)
261
- - Support [OIDC 1.0 Private Key JWT](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication); based on the OAuth JWT assertion specification [(RFC 7523)](https://tools.ietf.org/html/rfc7523)
262
- - Support new formats, including from [jsonapi.org](http://jsonapi.org/format/): `application/vdn.api+json`, `application/vnd.collection+json`, `application/hal+json`, `application/problem+json`
263
- - Adds option to `OAuth2::Client#get_token`:
264
- - `:access_token_class` (`AccessToken`); user specified class to use for all calls to `get_token`
265
- - Adds option to `OAuth2::AccessToken#initialize`:
266
- - `:expires_latency` (`nil`); number of seconds by which AccessToken validity will be reduced to offset latency
267
- - By default, keys are transformed to snake case.
268
- - Original keys will still work as previously, in most scenarios, thanks to [snaky_hash][snaky_hash] gem.
269
- - However, this is a _breaking_ change if you rely on `response.parsed.to_h` to retain the original case, and the original wasn't snake case, as the keys in the result will be snake case.
270
- - As of version 2.0.4 you can turn key transformation off with the `snaky: false` option.
271
- - By default, the `:auth_scheme` is now `:basic_auth` (instead of `:request_body`)
272
- - Third-party strategies and gems may need to be updated if a provider was requiring client id/secret in the request body
273
- - [... A lot more](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md#200-2022-06-21-tag)
274
-
275
- [snaky_hash]: https://gitlab.com/ruby-oauth/snaky_hash
276
-
277
- ## Compatibility
278
-
279
- Targeted ruby compatibility is non-EOL versions of Ruby, currently 3.2, 3.3, and 3.4.
280
- Compatibility is further distinguished as "Best Effort Support" or "Incidental Support" for older versions of Ruby.
281
- This gem will install on Ruby versions >= v2.2 for 2.x releases.
282
- See `1-4-stable` branch for older rubies.
283
-
284
- <details markdown="1">
285
- <summary>Ruby Engine Compatibility Policy</summary>
286
-
287
- This gem is tested against MRI, JRuby, and Truffleruby.
288
- Each of those has varying versions that target a specific version of MRI Ruby.
289
- This gem should work in the just-listed Ruby engines according to the targeted MRI compatibility in the table below.
290
- If you would like to add support for additional engines,
291
- see [gemfiles/README.md](gemfiles/README.md), then submit a PR to the correct maintenance branch as according to the table below.
292
-
293
- </details>
294
-
295
- <details markdown="1">
296
- <summary>Ruby Version Compatibility Policy</summary>
297
-
298
- If something doesn't work on one of these interpreters, it's a bug.
299
-
300
- This library may inadvertently work (or seem to work) on other Ruby
301
- implementations; however, support will only be provided for the versions listed
302
- above.
303
-
304
- If you would like this library to support another Ruby version, you may
305
- volunteer to be a maintainer. Being a maintainer entails making sure all tests
306
- run and pass on that implementation. When something breaks on your
307
- implementation, you will be responsible for providing patches in a timely
308
- fashion. If critical issues for a particular implementation exist at the time
309
- of a major release, support for that Ruby version may be dropped.
310
-
311
- </details>
312
-
313
- | | Ruby OAuth2 Version | Maintenance Branch | Targeted Support | Best Effort Support | Incidental Support |
314
- |:----|---------------------|--------------------|----------------------|-------------------------|------------------------------|
315
- | 1️⃣ | 2.0.x | `main` | 3.2, 3.3, 3.4 | 2.5, 2.6, 2.7, 3.0, 3.1 | 2.2, 2.3, 2.4 |
316
- | 2️⃣ | 1.4.x | `1-4-stable` | 3.2, 3.3, 3.4 | 2.5, 2.6, 2.7, 3.0, 3.1 | 1.9, 2.0, 2.1, 2.2, 2.3, 2.4 |
317
- | 3️⃣ | older | N/A | Best of luck to you! | Please upgrade! | |
318
-
319
- NOTE: The 1.4 series will only receive critical security updates.
320
- See [SECURITY.md][🔐security] and [IRP.md][🔐irp].
321
-
322
244
  ## ⚙️ Configuration
323
245
 
324
246
  Global settings for the library:
@@ -395,7 +317,7 @@ client = OAuth2::Client.new(
395
317
  "client_secret",
396
318
  site: "https://example.org/nested/directory/on/your/server",
397
319
  authorize_url: "/jaunty/authorize/",
398
- token_url: "/stirrups/access_token",
320
+ token_url: "/stirrups/access_token"
399
321
  )
400
322
  # => #<OAuth2::Client:0x00000001204c8288 @id="client_id", @secret="client_sec...
401
323
  client.auth_code.authorize_url(redirect_uri: "http://localhost:8080/oauth2/callback")
@@ -573,7 +495,7 @@ client = OAuth2::Client.new(
573
495
  "client_id",
574
496
  "client_secret",
575
497
  site: "https://example.org",
576
- logger: Logger.new("example.log", "weekly"),
498
+ logger: Logger.new("example.log", "weekly")
577
499
  )
578
500
  ```
579
501
 
@@ -710,437 +632,14 @@ access = client.auth_code.get_token("code_value", redirect_uri: "http://localhos
710
632
  You can always use the `#request` method on the `OAuth2::Client` instance to make
711
633
  requests for tokens for any Authentication grant type.
712
634
 
713
- ## 📘 Comprehensive Usage
714
-
715
- ### Common Flows (end-to-end)
716
-
717
- - Authorization Code (server-side web app):
718
-
719
- ```ruby
720
- require "oauth2"
721
- client = OAuth2::Client.new(
722
- ENV["CLIENT_ID"],
723
- ENV["CLIENT_SECRET"],
724
- site: "https://provider.example.com",
725
- redirect_uri: "https://my.app.example.com/oauth/callback",
726
- )
727
-
728
- # Step 1: redirect user to consent
729
- state = SecureRandom.hex(16)
730
- auth_url = client.auth_code.authorize_url(scope: "openid profile email", state: state)
731
- # redirect_to auth_url
732
-
733
- # Step 2: handle the callback
734
- # params[:code], params[:state]
735
- raise "state mismatch" unless params[:state] == state
736
- access = client.auth_code.get_token(params[:code])
737
-
738
- # Step 3: call APIs
739
- profile = access.get("/api/v1/me").parsed
740
- ```
741
-
742
- - Client Credentials (machine-to-machine):
743
-
744
- ```ruby
745
- client = OAuth2::Client.new(ENV["CLIENT_ID"], ENV["CLIENT_SECRET"], site: "https://provider.example.com")
746
- access = client.client_credentials.get_token(audience: "https://api.example.com")
747
- resp = access.get("/v1/things")
748
- ```
749
-
750
- - Resource Owner Password (legacy; avoid when possible):
751
-
752
- ```ruby
753
- access = client.password.get_token("jdoe", "s3cret", scope: "read")
754
- ```
755
-
756
- #### Examples
757
-
758
- <details markdown="1">
759
- <summary>JHipster UAA (Spring Cloud) password grant example (legacy; avoid when possible)</summary>
760
-
761
- ```ruby
762
- # This converts a Postman/Net::HTTP multipart token request to oauth2 gem usage.
763
- # JHipster UAA typically exposes the token endpoint at /uaa/oauth/token.
764
- # The original snippet included:
765
- # - Basic Authorization header for the client (web_app:changeit)
766
- # - X-XSRF-TOKEN header from a cookie (some deployments require it)
767
- # - grant_type=password with username/password and client_id
768
- # Using oauth2 gem, you don't need to build multipart bodies; the gem sends
769
- # application/x-www-form-urlencoded as required by RFC 6749.
770
-
771
- require "oauth2"
772
-
773
- client = OAuth2::Client.new(
774
- "web_app", # client_id
775
- "changeit", # client_secret
776
- site: "http://localhost:8080/uaa",
777
- token_url: "/oauth/token", # absolute under site (or "oauth/token" relative)
778
- auth_scheme: :basic_auth, # sends HTTP Basic Authorization header
779
- )
780
-
781
- # If your UAA requires an XSRF header for the token call, provide it as a header.
782
- # Often this is not required for token endpoints, but if your gateway enforces it,
783
- # obtain the value from the XSRF-TOKEN cookie and pass it here.
784
- xsrf_token = ENV["X_XSRF_TOKEN"] # e.g., pulled from a prior set-cookie value
785
-
786
- access = client.password.get_token(
787
- "admin", # username
788
- "admin", # password
789
- headers: xsrf_token ? {"X-XSRF-TOKEN" => xsrf_token} : {},
790
- # JHipster commonly also accepts/needs the client_id in the body; include if required:
791
- # client_id: "web_app",
792
- )
793
-
794
- puts access.token
795
- puts access.to_hash # full token response
796
- ```
797
-
798
- Notes:
799
-
800
- - Resource Owner Password Credentials (ROPC) is deprecated in OAuth 2.1 and discouraged. Prefer Authorization Code + PKCE.
801
- - 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.
802
- - For Basic auth, auth_scheme: :basic_auth handles the Authorization header; you do not need to base64-encode manually.
803
-
804
- </details>
805
-
806
- ### Verb‑dependent Token Mode
807
-
808
- Providers like Instagram require the access token to be sent differently depending on the HTTP verb:
809
-
810
- - GET requests: token must be in the query string (?access_token=...)
811
- - POST/DELETE requests: token must be in the Authorization header (Bearer ...)
812
-
813
- Since v2.0.15, you can configure an AccessToken with a verb‑dependent mode. The gem will choose how to send the token based on the request method.
814
-
815
- Tips:
816
-
817
- - Avoid query‑string bearer tokens unless required by your provider. Instagram explicitly requires it for `GET` requests.
818
- - If you need a custom rule, you can pass a `Proc` for `mode`, e.g. `mode: ->(verb) { verb == :get ? :query : :header }`.
819
-
820
- <details markdown="1">
821
- <summary>Instagram API Example</summary>
822
-
823
- Example: exchanging and refreshing long‑lived Instagram tokens, and making API calls
824
-
825
- ```ruby
826
- require "oauth2"
827
-
828
- # NOTE: Users authenticate via Facebook Login to obtain a short‑lived user token (not shown here).
829
- # See Facebook Login docs for obtaining the initial short‑lived token.
830
-
831
- client = OAuth2::Client.new(nil, nil, site: "https://graph.instagram.com")
832
-
833
- # Start with a short‑lived token you already obtained via Facebook Login
834
- short_lived = OAuth2::AccessToken.new(
835
- client,
836
- ENV["IG_SHORT_LIVED_TOKEN"],
837
- # Key part: verb‑dependent mode
838
- mode: {get: :query, post: :header, delete: :header},
839
- )
840
-
841
- # 1) Exchange for a long‑lived token (Instagram requires GET with access_token in query)
842
- # Endpoint: GET https://graph.instagram.com/access_token
843
- # Params: grant_type=ig_exchange_token, client_secret=APP_SECRET
844
- exchange = short_lived.get(
845
- "/access_token",
846
- params: {
847
- grant_type: "ig_exchange_token",
848
- client_secret: ENV["IG_APP_SECRET"],
849
- # access_token param will be added automatically by the AccessToken (mode => :query for GET)
850
- },
851
- )
852
- long_lived_token_value = exchange.parsed["access_token"]
853
-
854
- long_lived = OAuth2::AccessToken.new(
855
- client,
856
- long_lived_token_value,
857
- mode: {get: :query, post: :header, delete: :header},
858
- )
859
-
860
- # 2) Refresh the long‑lived token (Instagram uses GET with token in query)
861
- # Endpoint: GET https://graph.instagram.com/refresh_access_token
862
- refresh_resp = long_lived.get(
863
- "/refresh_access_token",
864
- params: {grant_type: "ig_refresh_token"},
865
- )
866
- long_lived = OAuth2::AccessToken.new(
867
- client,
868
- refresh_resp.parsed["access_token"],
869
- mode: {get: :query, post: :header, delete: :header},
870
- )
871
-
872
- # 3) Typical API GET request (token in query automatically)
873
- me = long_lived.get("/me", params: {fields: "id,username"}).parsed
874
-
875
- # 4) Example POST (token sent via Bearer header automatically)
876
- # Note: Replace the path/params with a real Instagram Graph API POST you need,
877
- # such as publishing media via the Graph API endpoints.
878
- # long_lived.post("/me/media", body: {image_url: "https://...", caption: "hello"})
879
- ```
880
-
881
- </details>
882
-
883
- ### Refresh Tokens
884
-
885
- When the server issues a refresh_token, you can refresh manually or implement an auto-refresh wrapper.
886
-
887
- - Manual refresh:
888
-
889
- ```ruby
890
- if access.expired?
891
- access = access.refresh
892
- end
893
- ```
894
-
895
- - Auto-refresh wrapper pattern:
896
-
897
- ```ruby
898
- class AutoRefreshingToken
899
- def initialize(token_provider, store: nil)
900
- @token = token_provider
901
- @store = store # e.g., something that responds to read/write for token data
902
- end
903
-
904
- def with(&blk)
905
- tok = ensure_fresh!
906
- blk ? blk.call(tok) : tok
907
- rescue OAuth2::Error => e
908
- # If a 401 suggests token invalidation, try one refresh and retry once
909
- if e.response && e.response.status == 401 && @token.refresh_token
910
- @token = @token.refresh
911
- @store.write(@token.to_hash) if @store
912
- retry
913
- end
914
- raise
915
- end
916
-
917
- private
918
-
919
- def ensure_fresh!
920
- if @token.expired? && @token.refresh_token
921
- @token = @token.refresh
922
- @store.write(@token.to_hash) if @store
923
- end
924
- @token
925
- end
926
- end
927
-
928
- # usage
929
- keeper = AutoRefreshingToken.new(access)
930
- keeper.with { |tok| tok.get("/v1/protected") }
931
- ```
932
-
933
- Persist the token across processes using `AccessToken#to_hash` and `AccessToken.from_hash(client, hash)`.
934
-
935
- ### Token Revocation (RFC 7009)
936
-
937
- You can revoke either the access token or the refresh token.
938
-
939
- ```ruby
940
- # Revoke the current access token
941
- access.revoke(token_type_hint: :access_token)
942
-
943
- # Or explicitly revoke the refresh token (often also invalidates associated access tokens)
944
- access.revoke(token_type_hint: :refresh_token)
945
- ```
946
-
947
- ### Client Configuration Tips
948
-
949
- #### Mutual TLS (mTLS) client authentication
950
-
951
- Some providers require OAuth requests (including the token request and subsequent API calls) to be sender‑constrained using mutual TLS (mTLS). With this gem, you enable mTLS by providing a client certificate/private key to Faraday via connection_opts.ssl and, if your provider requires it for client authentication, selecting the tls_client_auth auth_scheme.
952
-
953
- Example using PEM files (certificate and key):
954
-
955
- ```ruby
956
- require "oauth2"
957
- require "openssl"
958
-
959
- client = OAuth2::Client.new(
960
- ENV.fetch("CLIENT_ID"),
961
- ENV.fetch("CLIENT_SECRET"),
962
- site: "https://example.com",
963
- authorize_url: "/oauth/authorize/",
964
- token_url: "/oauth/token/",
965
- auth_scheme: :tls_client_auth, # if your AS requires mTLS-based client authentication
966
- connection_opts: {
967
- ssl: {
968
- client_cert: OpenSSL::X509::Certificate.new(File.read("localhost.pem")),
969
- client_key: OpenSSL::PKey::RSA.new(File.read("localhost-key.pem")),
970
- # Optional extras, uncomment as needed:
971
- # ca_file: "/path/to/ca-bundle.pem", # custom CA(s)
972
- # verify: true # enable server cert verification (recommended)
973
- },
974
- },
975
- )
976
-
977
- # Example token request (any grant type can be used). The mTLS handshake
978
- # will occur automatically on HTTPS calls using the configured cert/key.
979
- access = client.client_credentials.get_token
980
-
981
- # Subsequent resource requests will also use mTLS on HTTPS endpoints of `site`:
982
- resp = access.get("/v1/protected")
983
- ```
984
-
985
- Notes:
986
-
987
- - 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"])`.
988
- - If your certificate and key are in a PKCS#12/PFX bundle, you can load them like:
989
- - `p12 = OpenSSL::PKCS12.new(File.read("client.p12"), ENV["P12_PASSWORD"])`
990
- - `client_cert = p12.certificate; client_key = p12.key`
991
- - Server trust:
992
- - If your environment does not have system CAs, specify `ca_file` or `ca_path` inside the `ssl:` hash.
993
- - Keep `verify: true` in production. Set `verify: false` only for local testing.
994
- - Faraday adapter: Any adapter that supports Ruby’s OpenSSL should work. `net_http` (default) and `net_http_persistent` are common choices.
995
- - 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).
996
- - 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.
997
-
998
- #### Authentication schemes for the token request
999
-
1000
- ```ruby
1001
- OAuth2::Client.new(
1002
- id,
1003
- secret,
1004
- site: "https://provider.example.com",
1005
- auth_scheme: :basic_auth, # default. Alternatives: :request_body, :tls_client_auth, :private_key_jwt
1006
- )
1007
- ```
1008
-
1009
- #### Faraday connection, timeouts, proxy, custom adapter/middleware:
1010
-
1011
- ```ruby
1012
- client = OAuth2::Client.new(
1013
- id,
1014
- secret,
1015
- site: "https://provider.example.com",
1016
- connection_opts: {
1017
- request: {open_timeout: 5, timeout: 15},
1018
- proxy: ENV["HTTPS_PROXY"],
1019
- ssl: {verify: true},
1020
- },
1021
- ) do |faraday|
1022
- faraday.request(:url_encoded)
1023
- # faraday.response :logger, Logger.new($stdout) # see OAUTH_DEBUG below
1024
- faraday.adapter(:net_http_persistent) # or any Faraday adapter you need
1025
- end
1026
- ```
1027
-
1028
- ##### Using flat query params (`Faraday::FlatParamsEncoder`)
1029
-
1030
- Some APIs expect repeated key parameters to be sent as flat params rather than arrays. Faraday provides `FlatParamsEncoder` for this purpose. You can configure the oauth2 client to use it when building requests.
1031
-
1032
- ```ruby
1033
- require "faraday"
1034
-
1035
- client = OAuth2::Client.new(
1036
- id,
1037
- secret,
1038
- site: "https://api.example.com",
1039
- # Pass Faraday connection options to make FlatParamsEncoder the default
1040
- connection_opts: {
1041
- request: {params_encoder: Faraday::FlatParamsEncoder},
1042
- },
1043
- ) do |faraday|
1044
- faraday.request(:url_encoded)
1045
- faraday.adapter(:net_http)
1046
- end
1047
-
1048
- access = client.client_credentials.get_token
1049
-
1050
- # Example of a GET with two flat filter params (not an array):
1051
- # Results in: ?filter=order.clientCreatedTime%3E1445006997000&filter=order.clientCreatedTime%3C1445611797000
1052
- resp = access.get(
1053
- "/v1/orders",
1054
- params: {
1055
- # Provide the values as an array; FlatParamsEncoder expands them as repeated keys
1056
- filter: [
1057
- "order.clientCreatedTime>1445006997000",
1058
- "order.clientCreatedTime<1445611797000",
1059
- ],
1060
- },
1061
- )
1062
- ```
1063
-
1064
- If you instead need to build a raw Faraday connection yourself, the equivalent configuration is:
1065
-
1066
- ```ruby
1067
- conn = Faraday.new("https://api.example.com", request: {params_encoder: Faraday::FlatParamsEncoder})
1068
- ```
1069
-
1070
- #### Redirection
1071
-
1072
- The library follows up to `max_redirects` (default 5).
1073
- You can override per-client via `options[:max_redirects]`.
1074
-
1075
- ### Handling Responses and Errors
1076
-
1077
- - Parsing:
1078
-
1079
- ```ruby
1080
- resp = access.get("/v1/thing")
1081
- resp.status # Integer
1082
- resp.headers # Hash
1083
- resp.body # String
1084
- resp.parsed # SnakyHash::StringKeyed or Array when JSON array
1085
- ```
1086
-
1087
- - Error handling:
1088
-
1089
- ```ruby
1090
- begin
1091
- access.get("/v1/forbidden")
1092
- rescue OAuth2::Error => e
1093
- e.code # OAuth2 error code (when present)
1094
- e.description # OAuth2 error description (when present)
1095
- e.response # OAuth2::Response (full access to status/headers/body)
1096
- end
1097
- ```
1098
-
1099
- - Disable raising on 4xx/5xx to inspect the response yourself:
1100
-
1101
- ```ruby
1102
- client = OAuth2::Client.new(id, secret, site: site, raise_errors: false)
1103
- res = client.request(:get, "/v1/maybe-errors")
1104
- if res.status == 429
1105
- sleep res.headers["retry-after"].to_i
1106
- end
1107
- ```
1108
-
1109
- ### Making Raw Token Requests
1110
-
1111
- If a provider requires non-standard parameters or headers, you can call `client.get_token` directly:
1112
-
1113
- ```ruby
1114
- access = client.get_token({
1115
- grant_type: "client_credentials",
1116
- audience: "https://api.example.com",
1117
- headers: {"X-Custom" => "value"},
1118
- parse: :json, # override parsing
1119
- })
1120
- ```
1121
-
1122
- ### OpenID Connect (OIDC)
1123
-
1124
- - If the token response includes an `id_token` (a JWT), this gem surfaces it in `token.params['id_token']`.
1125
- - **Note**: This gem does **not** validate the signature of the `id_token`. You must use a JWT library (like the `jwt` [gem](https://github.com/jwt/ruby-jwt)) and your provider's JWKs to verify it.
1126
- - For `private_key_jwt` client authentication, provide `auth_scheme: :private_key_jwt` and ensure your key configuration matches the provider requirements.
1127
- - See [OIDC.md](OIDC.md) for a more complete OIDC overview and examples.
1128
-
1129
- ### Debugging
1130
-
1131
- - Set environment variable `OAUTH_DEBUG=true` to enable verbose Faraday logging (uses the client-provided logger).
1132
- - To mirror a working curl request, ensure you set the same auth scheme, params, and content type. The Quick Example at the top shows a curl-to-ruby translation.
1133
-
1134
- ---
1135
-
1136
635
  ## 🦷 FLOSS Funding
1137
636
 
1138
637
  While ruby-oauth tools are free software and will always be, the project would benefit immensely from some funding.
1139
638
  Raising a monthly budget of... "dollars" would make the project more sustainable.
1140
639
 
1141
640
  We welcome both individual and corporate sponsors! We also offer a
1142
- wide array of funding channels to account for your preferences
1143
- (although currently [Open Collective][🖇osc] is our preferred funding platform).
641
+ wide array of funding channels to account for your preferences.
642
+ Currently, [Open Collective][🖇osc] is our preferred funding platform.
1144
643
 
1145
644
  **If you're working in a company that's making significant use of ruby-oauth tools we'd
1146
645
  appreciate it if you suggest to your company to become a ruby-oauth sponsor.**
@@ -1152,7 +651,7 @@ You can support the development of ruby-oauth tools via
1152
651
  [Open Collective][🖇osc]
1153
652
  and [Tidelift][🏙️entsup-tidelift].
1154
653
 
1155
- | 📍 NOTE |
654
+ | 📍 NOTE |
1156
655
  |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
1157
656
  | If doing a sponsorship in the form of donation is problematic for your company <br/> from an accounting standpoint, we'd recommend the use of Tidelift, <br/> where you can get a support-like subscription instead. |
1158
657
 
@@ -1177,14 +676,14 @@ No sponsors yet. Be the first!
1177
676
 
1178
677
  ### Open Collective for Donors
1179
678
 
1180
- [Bill Woika](https://opencollective.com/bill-woika)
679
+ [Bill Woika](https://opencollective.com/bill-woika) [Philipp Ebneter](https://opencollective.com/guest-e77282f7) [Grigoriy](https://opencollective.com/guest-c93e0c48)
1181
680
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:END -->
1182
681
 
1183
- [kettle-readme-backers]: https://github.com/ruby-oauth/oauth2/blob/main/exe/kettle-readme-backers
682
+ [kettle-readme-backers]: https://github.com/ruby-oauth/oauth2/blob/main/bin/kettle-readme-backers
1184
683
 
1185
684
  ### Another way to support open-source
1186
685
 
1187
- 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).
686
+ 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).
1188
687
 
1189
688
  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`.
1190
689
 
@@ -1196,15 +695,12 @@ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed
1196
695
 
1197
696
  ## 🔐 Security
1198
697
 
1199
- To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
1200
- Tidelift will coordinate the fix and disclosure.
1201
-
1202
- For more see [SECURITY.md][🔐security], [THREAT_MODEL.md][🔐threat-model], and [IRP.md][🔐irp].
698
+ See [SECURITY.md][🔐security].
1203
699
 
1204
700
  ## 🤝 Contributing
1205
701
 
1206
702
  If you need some ideas of where to help, you could work on adding more code coverage,
1207
- or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
703
+ or if it is already 💯 (see [below](#code-coverage)) check [issues][🤝gh-issues] or [PRs][🤝gh-pulls],
1208
704
  or use the gem and think about how it could be better.
1209
705
 
1210
706
  We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
@@ -1217,12 +713,17 @@ See [CONTRIBUTING.md][🤝contributing].
1217
713
 
1218
714
  ### Code Coverage
1219
715
 
716
+ <details markdown="1">
717
+ <summary>Coverage service badges</summary>
718
+
1220
719
  [![Coverage Graph][🏀codecov-g]][🏀codecov]
1221
720
 
1222
721
  [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
1223
722
 
1224
723
  [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
1225
724
 
725
+ </details>
726
+
1226
727
  ### 🪇 Code of Conduct
1227
728
 
1228
729
  Everyone interacting with this project's codebases, issue trackers,
@@ -1237,13 +738,13 @@ Made with [contributors-img][🖐contrib-rocks].
1237
738
  Also see GitLab Contributors: [https://gitlab.com/ruby-oauth/oauth2/-/graphs/main][🚎contributors-gl]
1238
739
 
1239
740
  <details>
1240
- <summary>⭐️ Star History</summary>
741
+ <summary>⭐️ Star History</summary>
1241
742
 
1242
- <a href="https://star-history.com/#ruby-oauth/oauth2&Date">
743
+ <a href="https://star-history.com/ruby-oauth/oauth2&Date">
1243
744
  <picture>
1244
- <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=ruby-oauth/oauth2&type=Date&theme=dark" />
1245
- <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=ruby-oauth/oauth2&type=Date" />
1246
- <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=ruby-oauth/oauth2&type=Date" />
745
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=ruby-oauth/oauth2&type=Date&theme=dark" />
746
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=ruby-oauth/oauth2&type=Date" />
747
+ <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=ruby-oauth/oauth2&type=Date" />
1247
748
  </picture>
1248
749
  </a>
1249
750
 
@@ -1251,19 +752,8 @@ Also see GitLab Contributors: [https://gitlab.com/ruby-oauth/oauth2/-/graphs/mai
1251
752
 
1252
753
  ## 📌 Versioning
1253
754
 
1254
- This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
1255
- Violations of this scheme should be reported as bugs.
1256
- Specifically, if a minor or patch version is released that breaks backward compatibility,
1257
- a new version should be immediately released that restores compatibility.
1258
- Breaking changes to the public API will only be introduced with new major versions.
1259
-
1260
- > dropping support for a platform is both obviously and objectively a breaking change <br/>
1261
- >—Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
1262
-
1263
- I understand that policy doesn't work universally ("exceptions to every rule!"),
1264
- but it is the policy here.
1265
- As such, in many cases it is good to specify a dependency on this library using
1266
- the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
755
+ This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
756
+ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
1267
757
 
1268
758
  For example:
1269
759
 
@@ -1274,8 +764,8 @@ spec.add_dependency("oauth2", "~> 2.0")
1274
764
  <details markdown="1">
1275
765
  <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
1276
766
 
1277
- SemVer should, IMO, but doesn't explicitly, say that dropping support for specific Platforms
1278
- is a *breaking change* to an API, and for that reason the bike shedding is endless.
767
+ Dropping support for a platform can be a breaking change for affected users.
768
+ If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.
1279
769
 
1280
770
  To get a better understanding of how SemVer is intended to work over a project's lifetime,
1281
771
  read this article from the creator of SemVer:
@@ -1289,25 +779,119 @@ See [CHANGELOG.md][📌changelog] for a list of releases.
1289
779
  ## 📄 License
1290
780
 
1291
781
  The gem is available as open source under the terms of
1292
- the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
1293
- See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
782
+ the [MIT](MIT.md) [![License: MIT][📄license-img]][📄license-ref].
1294
783
 
1295
784
  ### © Copyright
1296
785
 
1297
- <ul>
1298
- <li>
1299
- Copyright (c) 2017 – 2026 Peter H. Boling, of
1300
- <a href="https://discord.gg/3qme4XHNKN">
1301
- Galtzo.com
1302
- <picture>
1303
- <img src="https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px-blank.svg" alt="Galtzo.com Logo (Wordless) by Aboling0, CC BY-SA 4.0" width="24">
1304
- </picture>
1305
- </a>, and oauth2 contributors.
1306
- </li>
1307
- <li>
1308
- Copyright (c) 2011 - 2013 Michael Bleigh and Intridea, Inc.
1309
- </li>
1310
- </ul>
786
+ See [LICENSE.md][📄license] for the official copyright notice.
787
+
788
+ <details markdown="1">
789
+ <summary>Copyright holders</summary>
790
+
791
+ - Copyright (c) 2010-2014, 2016-2017 Erik Michaels-Ober
792
+ - Copyright (c) 2010 Jeremy Kemper
793
+ - Copyright (c) 2010-2011 Michael Bleigh
794
+ - Copyright (c) 2010-2011 Paul Walker
795
+ - Copyright (c) 2010 rick
796
+ - Copyright (c) 2010 Tim Habermaas
797
+ - Copyright (c) 2010 Wynn Netherland
798
+ - Copyright (c) 2011 Alexander Lang
799
+ - Copyright (c) 2011 Alexander Lang
800
+ - Copyright (c) 2011 Greg Spurrier
801
+ - Copyright (c) 2011 Jay Adkisson
802
+ - Copyright (c) 2011 Luke Saunders
803
+ - Copyright (c) 2011 Paul Walker
804
+ - Copyright (c) 2011 Simon Gate
805
+ - Copyright (c) 2012 Bas Vodde
806
+ - Copyright (c) 2012 Damian Janowski
807
+ - Copyright (c) 2012 Daniël van de Burgt
808
+ - Copyright (c) 2012 Dorren Chen
809
+ - Copyright (c) 2012 Igor Sales
810
+ - Copyright (c) 2012 Leigh Caplan
811
+ - Copyright (c) 2012 Michael Andrews
812
+ - Copyright (c) 2012 Omer Rauchwerger
813
+ - Copyright (c) 2012 Saverio Trioni
814
+ - Copyright (c) 2012 Trent Ogren
815
+ - Copyright (c) 2012 Vsevolod Romashov
816
+ - Copyright (c) 2013 Antonio Tapiador del Dujo
817
+ - Copyright (c) 2013 Eduardo Gurgel
818
+ - Copyright (c) 2013 Geostellar Developer
819
+ - Copyright (c) 2013-2014, 2018 Niels Ganser
820
+ - Copyright (c) 2013 Rainux Luo
821
+ - Copyright (c) 2013 Taylor Hedberg
822
+ - Copyright (c) 2013 Tim Clem
823
+ - Copyright (c) 2014 Dave Stevens
824
+ - Copyright (c) 2014 Ellis Berner
825
+ - Copyright (c) 2014 Frank Macreery
826
+ - Copyright (c) 2014 Michael Bleigh
827
+ - Copyright (c) 2014 Olivier Lacan
828
+ - Copyright (c) 2014 Peter Souter
829
+ - Copyright (c) 2014 Ryan Williams
830
+ - Copyright (c) 2015 Andrew Cantino and Jeff Moore
831
+ - Copyright (c) 2015 Thomas Walpole
832
+ - Copyright (c) 2016 Bo Jeanes
833
+ - Copyright (c) 2016 Cody Cutrer
834
+ - Copyright (c) 2016 Edward Rudd
835
+ - Copyright (c) 2016 Lawrence Oluyede
836
+ - Copyright (c) 2016 Linus Pettersson
837
+ - Copyright (c) 2016 Motoshi Nishihira
838
+ - Copyright (c) 2017 Adrian Setyadi
839
+ - Copyright (c) 2017-2018 Benjamin Quorning
840
+ - Copyright (c) 2017 Christoph Petschnig
841
+ - Copyright (c) 2017, 2022 Nathaniel Bibler
842
+ - Copyright (c) 2017 Oleg
843
+ - Copyright (c) 2017 Samuel Cochran
844
+ - Copyright (c) 2017 tetsuya
845
+ - Copyright (c) 2017 Yury Velikanau
846
+ - Copyright (c) 2018 Alex Kowalczuk
847
+ - Copyright (c) 2018 asm__
848
+ - Copyright (c) 2018 David Christensen
849
+ - Copyright (c) 2018 fossabot
850
+ - Copyright (c) 2018 Jeff Moore
851
+ - Copyright (c) 2018 Jeff Moore
852
+ - Copyright (c) 2018 Jonathan del Strother
853
+ - Copyright (c) 2018 Joseph Page
854
+ - Copyright (c) 2018 Joseph Page
855
+ - Copyright (c) 2018 Lomey
856
+ - Copyright (c) 2018 Markus Bengts
857
+ - Copyright (c) 2018 Mathias Klippinge
858
+ - Copyright (c) 2018 nikz
859
+ - Copyright (c) 2018-2019, 2021-2022, 2024-2026 Peter H. Boling
860
+ - Copyright (c) 2019 Daniel Fockler
861
+ - Copyright (c) 2019 Elliot Crosby-McCullough
862
+ - Copyright (c) 2019 João Paulo
863
+ - Copyright (c) 2019 Orien Madgwick
864
+ - Copyright (c) 2019 Ryan T. Hosford
865
+ - Copyright (c) 2019 Tom Corley
866
+ - Copyright (c) 2020 anvox
867
+ - Copyright (c) 2020 Jesse Cotton
868
+ - Copyright (c) 2020 Olle Jonsson
869
+ - Copyright (c) 2020 Stephen Reid
870
+ - Copyright (c) 2021 Anders Carling
871
+ - Copyright (c) 2021 dobon
872
+ - Copyright (c) 2021 Jan Zaydowicz
873
+ - Copyright (c) 2021 Nicholas Palaniuk
874
+ - Copyright (c) 2021-2022 Stan Hu
875
+ - Copyright (c) 2022 Benjamin Quorning
876
+ - Copyright (c) 2022 Bouke van der Bijl
877
+ - Copyright (c) 2022 nov
878
+ - Copyright (c) 2022 Rick Selby
879
+ - Copyright (c) 2022 Ryo Takahashi
880
+ - Copyright (c) 2023 Jessie Young
881
+ - Copyright (c) 2023 Карим Гимадеев
882
+ - Copyright (c) 2024 Aboling0
883
+ - Copyright (c) 2024 Elise Wood
884
+ - Copyright (c) 2024 Manuel van Rijn
885
+ - Copyright (c) 2025-2026 Annibelle Boling
886
+ - Copyright (c) 2025 Mark James
887
+ - Copyright (c) 2025 Mridang Agarwalla
888
+ - Copyright (c) 2025 Sasa Rosic
889
+ - Copyright (c) 2026 Jonathan Grinstead
890
+ - Copyright (c) 2026 kain
891
+ - Copyright (c) 2026 Rob Zolkos
892
+ - Copyright (c) 2026 StepSecurity Bot
893
+
894
+ </details>
1311
895
 
1312
896
  ## 🤑 A request for help
1313
897
 
@@ -1328,6 +912,8 @@ To say "thanks!" ☝️ Join the Discord or 👇️ send money.
1328
912
 
1329
913
  ### Please give the project a star ⭐ ♥.
1330
914
 
915
+ Many parts of this project are actively managed by a [kettle-jem](https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/kettle-jem) smart template utilizing [StructuredMerge.org](https://structuredmerge.org) merge contracts.
916
+
1331
917
  Thanks for RTFM. ☺️
1332
918
 
1333
919
  [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
@@ -1350,7 +936,7 @@ Thanks for RTFM. ☺️
1350
936
  [🖇polar-img]: https://img.shields.io/badge/polar-donate-a51611.svg?style=flat
1351
937
  [🖇polar]: https://polar.sh/pboling
1352
938
  [🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
1353
- [🖇kofi]: https://ko-fi.com/O5O86SNP4
939
+ [🖇kofi]: https://ko-fi.com/pboling
1354
940
  [🖇patreon-img]: https://img.shields.io/badge/patreon-donate-a51611.svg?style=flat
1355
941
  [🖇patreon]: https://patreon.com/galtzo
1356
942
  [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
@@ -1366,22 +952,19 @@ Thanks for RTFM. ☺️
1366
952
  [✉️ruby-friends-img]: https://img.shields.io/badge/daily.dev-%F0%9F%92%8E_Ruby_Friends-0A0A0A?style=for-the-badge&logo=dailydotdev&logoColor=white
1367
953
  [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
1368
954
 
1369
- [⛳gg-discussions]: https://groups.google.com/g/oauth-ruby
1370
- [⛳gg-discussions-img]: https://img.shields.io/badge/google-group-0093D0.svg?style=for-the-badge&logo=google&logoColor=orange
1371
-
1372
955
  [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
1373
956
  [⛳️gem-namespace]: https://github.com/ruby-oauth/oauth2
1374
957
  [⛳️namespace-img]: https://img.shields.io/badge/namespace-OAuth2-3C2D2D.svg?style=square&logo=ruby&logoColor=white
1375
958
  [⛳️gem-name]: https://bestgems.org/gems/oauth2
1376
959
  [⛳️name-img]: https://img.shields.io/badge/name-oauth2-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
1377
960
  [⛳️tag-img]: https://img.shields.io/github/tag/ruby-oauth/oauth2.svg
1378
- [⛳️tag]: http://github.com/ruby-oauth/oauth2/releases
961
+ [⛳️tag]: https://github.com/ruby-oauth/oauth2/releases
1379
962
  [🚂maint-blog]: http://www.railsbling.com/tags/oauth2
1380
963
  [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
1381
964
  [🚂maint-contact]: http://www.railsbling.com/contact
1382
965
  [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
1383
966
  [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
1384
- [💖🖇linkedin-img]: https://img.shields.io/badge/PeterBoling-LinkedIn-0B66C2?style=flat&logo=newjapanprowrestling
967
+ [💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat&logo=newjapanprowrestling
1385
968
  [💖✌️wellfound]: https://wellfound.com/u/peter-boling
1386
969
  [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
1387
970
  [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
@@ -1410,7 +993,7 @@ Thanks for RTFM. ☺️
1410
993
  [💁🏼‍♂️peterboling]: http://www.peterboling.com
1411
994
  [🚂railsbling]: http://www.railsbling.com
1412
995
  [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
1413
- [📜src-gl]: https://gitlab.com/ruby-oauth/oauth2/
996
+ [📜src-gl]: https://gitlab.com/ruby-oauth/oauth2
1414
997
  [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
1415
998
  [📜src-cb]: https://codeberg.org/ruby-oauth/oauth2
1416
999
  [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green
@@ -1419,8 +1002,8 @@ Thanks for RTFM. ☺️
1419
1002
  [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
1420
1003
  [📜gl-wiki]: https://gitlab.com/ruby-oauth/oauth2/-/wikis/home
1421
1004
  [📜gh-wiki]: https://github.com/ruby-oauth/oauth2/wiki
1422
- [📜gl-wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
1423
- [📜gh-wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
1005
+ [📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
1006
+ [📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
1424
1007
  [👽dl-rank]: https://bestgems.org/gems/oauth2
1425
1008
  [👽dl-ranki]: https://img.shields.io/gem/rd/oauth2.svg
1426
1009
  [👽version]: https://bestgems.org/gems/oauth2
@@ -1433,32 +1016,37 @@ Thanks for RTFM. ☺️
1433
1016
  [🏀codecovi]: https://codecov.io/gh/ruby-oauth/oauth2/graph/badge.svg
1434
1017
  [🏀coveralls]: https://coveralls.io/github/ruby-oauth/oauth2?branch=main
1435
1018
  [🏀coveralls-img]: https://coveralls.io/repos/github/ruby-oauth/oauth2/badge.svg?branch=main
1436
- [🖐codeQL]: https://github.com/ruby-oauth/oauth2/security/code-scanning
1437
- [🖐codeQL-img]: https://github.com/ruby-oauth/oauth2/actions/workflows/codeql-analysis.yml/badge.svg
1438
- [🚎1-an-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ancient.yml
1439
- [🚎1-an-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/ancient.yml/badge.svg
1019
+ [🚎ruby-2.4-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ruby-2.4.yml
1020
+ [🚎ruby-2.5-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ruby-2.5.yml
1021
+ [🚎ruby-2.6-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ruby-2.6.yml
1022
+ [🚎ruby-2.7-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ruby-2.7.yml
1023
+ [🚎ruby-3.0-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ruby-3.0.yml
1024
+ [🚎ruby-3.1-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ruby-3.1.yml
1025
+ [🚎ruby-3.2-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ruby-3.2.yml
1026
+ [🚎ruby-3.3-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ruby-3.3.yml
1027
+ [🚎ruby-3.4-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ruby-3.4.yml
1028
+ [🚎jruby-9.2-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/jruby-9.2.yml
1029
+ [🚎jruby-9.3-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/jruby-9.3.yml
1030
+ [🚎jruby-9.4-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/jruby-9.4.yml
1031
+ [🚎truby-22.3-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/truffleruby-22.3.yml
1032
+ [🚎truby-23.0-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/truffleruby-23.0.yml
1033
+ [🚎truby-23.1-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/truffleruby-23.1.yml
1034
+ [🚎truby-24.2-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/truffleruby-24.2.yml
1035
+ [🚎truby-25.0-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/truffleruby-25.0.yml
1440
1036
  [🚎2-cov-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/coverage.yml
1441
1037
  [🚎2-cov-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/coverage.yml/badge.svg
1442
1038
  [🚎3-hd-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/heads.yml
1443
1039
  [🚎3-hd-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/heads.yml/badge.svg
1444
- [🚎4-lg-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/legacy.yml
1445
- [🚎4-lg-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/legacy.yml/badge.svg
1446
1040
  [🚎5-st-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/style.yml
1447
1041
  [🚎5-st-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/style.yml/badge.svg
1448
- [🚎6-s-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/supported.yml
1449
- [🚎6-s-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/supported.yml/badge.svg
1450
- [🚎7-us-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/unsupported.yml
1451
- [🚎7-us-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/unsupported.yml/badge.svg
1452
- [🚎8-ho-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/hoary.yml
1453
- [🚎8-ho-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/hoary.yml/badge.svg
1042
+ [🚎9-t-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/truffle.yml
1043
+ [🚎9-t-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/truffle.yml/badge.svg
1454
1044
  [🚎10-j-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/jruby.yml
1455
1045
  [🚎10-j-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/jruby.yml/badge.svg
1456
1046
  [🚎11-c-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/current.yml
1457
1047
  [🚎11-c-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/current.yml/badge.svg
1458
1048
  [🚎12-crh-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/dep-heads.yml
1459
1049
  [🚎12-crh-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/dep-heads.yml/badge.svg
1460
- [🚎13-cbs-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/caboose.yml
1461
- [🚎13-cbs-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/caboose.yml/badge.svg
1462
1050
  [🚎13-🔒️-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/locked_deps.yml
1463
1051
  [🚎13-🔒️-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/locked_deps.yml/badge.svg
1464
1052
  [🚎14-🔓️-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/unlocked_deps.yml
@@ -1466,7 +1054,7 @@ Thanks for RTFM. ☺️
1466
1054
  [🚎15-🪪-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/license-eye.yml
1467
1055
  [🚎15-🪪-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/license-eye.yml/badge.svg
1468
1056
  [💎ruby-2.2i]: https://img.shields.io/badge/Ruby-2.2_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
1469
- [💎ruby-2.3i]: https://img.shields.io/badge/Ruby-2.3-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
1057
+ [💎ruby-2.3i]: https://img.shields.io/badge/Ruby-2.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
1470
1058
  [💎ruby-2.4i]: https://img.shields.io/badge/Ruby-2.4-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
1471
1059
  [💎ruby-2.5i]: https://img.shields.io/badge/Ruby-2.5-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
1472
1060
  [💎ruby-2.6i]: https://img.shields.io/badge/Ruby-2.6-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
@@ -1475,16 +1063,18 @@ Thanks for RTFM. ☺️
1475
1063
  [💎ruby-3.1i]: https://img.shields.io/badge/Ruby-3.1-CC342D?style=for-the-badge&logo=ruby&logoColor=white
1476
1064
  [💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white
1477
1065
  [💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
1066
+ [💎ruby-3.4i]: https://img.shields.io/badge/Ruby-3.4-CC342D?style=for-the-badge&logo=ruby&logoColor=white
1067
+ [💎ruby-4.0i]: https://img.shields.io/badge/Ruby-4.0-CC342D?style=for-the-badge&logo=ruby&logoColor=white
1478
1068
  [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
1479
1069
  [💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue
1480
- [💎truby-22.3i]: https://img.shields.io/badge/Truffle_Ruby-22.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=pink
1481
- [💎truby-23.0i]: https://img.shields.io/badge/Truffle_Ruby-23.0_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=pink
1482
- [💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=pink
1070
+ [💎truby-22.3i]: https://img.shields.io/badge/Truffle_Ruby-22.3-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
1071
+ [💎truby-23.0i]: https://img.shields.io/badge/Truffle_Ruby-23.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
1072
+ [💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
1073
+ [💎truby-24.2i]: https://img.shields.io/badge/Truffle_Ruby-24.2-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
1074
+ [💎truby-25.0i]: https://img.shields.io/badge/Truffle_Ruby-25.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
1483
1075
  [💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green
1484
- [💎truby-headi]: https://img.shields.io/badge/Truffle_Ruby-HEAD-34BCB1?style=for-the-badge&logo=ruby&logoColor=blue
1485
- [💎jruby-9.1i]: https://img.shields.io/badge/JRuby-9.1_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
1486
- [💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
1487
- [💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
1076
+ [💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2-FBE742?style=for-the-badge&logo=ruby&logoColor=red
1077
+ [💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3-FBE742?style=for-the-badge&logo=ruby&logoColor=red
1488
1078
  [💎jruby-9.4i]: https://img.shields.io/badge/JRuby-9.4-FBE742?style=for-the-badge&logo=ruby&logoColor=red
1489
1079
  [💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green
1490
1080
  [💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue
@@ -1495,38 +1085,35 @@ Thanks for RTFM. ☺️
1495
1085
  [🤝cb-issues]: https://codeberg.org/ruby-oauth/oauth2/issues
1496
1086
  [🤝cb-pulls]: https://codeberg.org/ruby-oauth/oauth2/pulls
1497
1087
  [🤝cb-donate]: https://donate.codeberg.org/
1498
- [🤝contributing]: CONTRIBUTING.md
1499
- [🏀codecov-g]: https://codecov.io/gh/ruby-oauth/oauth2/graphs/tree.svg
1088
+ [🤝contributing]: https://github.com/ruby-oauth/oauth2/blob/main/CONTRIBUTING.md
1089
+ [🏀codecov-g]: https://codecov.io/gh/ruby-oauth/oauth2/graph/badge.svg
1500
1090
  [🖐contrib-rocks]: https://contrib.rocks
1501
1091
  [🖐contributors]: https://github.com/ruby-oauth/oauth2/graphs/contributors
1502
1092
  [🖐contributors-img]: https://contrib.rocks/image?repo=ruby-oauth/oauth2
1503
1093
  [🚎contributors-gl]: https://gitlab.com/ruby-oauth/oauth2/-/graphs/main
1504
- [🪇conduct]: CODE_OF_CONDUCT.md
1094
+ [🪇conduct]: https://github.com/ruby-oauth/oauth2/blob/main/CODE_OF_CONDUCT.md
1505
1095
  [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
1506
1096
  [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
1507
1097
  [📌semver]: https://semver.org/spec/v2.0.0.html
1508
1098
  [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
1509
1099
  [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
1510
1100
  [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
1511
- [📌changelog]: CHANGELOG.md
1101
+ [📌changelog]: https://github.com/ruby-oauth/oauth2/blob/main/CHANGELOG.md
1512
1102
  [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
1513
1103
  [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
1514
1104
  [📌gitmoji]: https://gitmoji.dev
1515
1105
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1516
1106
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1517
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.527-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1518
- [🔐security]: SECURITY.md
1107
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.558-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1108
+ [🔐security]: https://github.com/ruby-oauth/oauth2/blob/main/SECURITY.md
1519
1109
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1520
- [🔐irp]: IRP.md
1521
- [🔐irp-img]: https://img.shields.io/badge/IRP-259D6C.svg?style=flat
1522
- [🔐threat-model]: THREAT_MODEL.md
1523
- [🔐threat-model-img]: https://img.shields.io/badge/threat-model-259D6C.svg?style=flat
1524
1110
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
1525
- [📄license]: LICENSE.txt
1526
- [📄license-ref]: https://opensource.org/licenses/MIT
1111
+ [📄license]: LICENSE.md
1112
+ [📄license-ref]: MIT.md
1527
1113
  [📄license-img]: https://img.shields.io/badge/License-MIT-259D6C.svg
1528
- [📄license-compat]: https://dev.to/galtzo/how-to-check-license-compatibility-41h0
1114
+ [📄license-compat]: https://www.apache.org/legal/resolved.html#category-a
1529
1115
  [📄license-compat-img]: https://img.shields.io/badge/Apache_Compatible:_Category_A-%E2%9C%93-259D6C.svg?style=flat&logo=Apache
1116
+
1530
1117
  [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
1531
1118
  [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
1532
1119
  [🚎yard-current]: http://rubydoc.info/gems/oauth2
@@ -1539,12 +1126,13 @@ Thanks for RTFM. ☺️
1539
1126
  [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
1540
1127
  [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
1541
1128
 
1542
- <details>
1543
- <summary>
1544
- rel="me" Social Proofs
1545
- </summary>
1546
-
1547
- <a rel="me" alt="Follow me on Ruby.social" href="https://ruby.social/@galtzo"><img src="https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=social&label=Follow%20@galtzo%20on%20Ruby.social"></a>
1548
- <a rel="me" alt="Follow me on FLOSS.social" href="https://floss.social/@galtzo"><img src="https://img.shields.io/mastodon/follow/110304921404405715?domain=https://floss.social&style=social&label=Follow%20@galtzo%20on%20Floss.social"></a>
1549
-
1550
- </details>
1129
+ <!-- kettle-jem:metadata:start -->
1130
+ | Field | Value |
1131
+ |---|---|
1132
+ | Package | oauth2 |
1133
+ | Description | 🔐 A Ruby wrapper for the OAuth 2.0 Authorization Framework, including the OAuth 2.1 draft spec, and OpenID Connect (OIDC) |
1134
+ | Homepage | https://github.com/ruby-oauth/oauth2 |
1135
+ | Source | https://github.com/ruby-oauth/oauth2 |
1136
+ | License | `MIT` |
1137
+ | Funding | https://github.com/sponsors/pboling, https://issuehunt.io/u/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://opencollective.com/ruby-oauth, https://patreon.com/galtzo, https://polar.sh/pboling, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/oauth2, https://www.buymeacoffee.com/pboling |
1138
+ <!-- kettle-jem:metadata:end -->