oauth2 2.0.12 → 2.0.14

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,55 +1,97 @@
1
- <p align="center">
2
- <a href="https://discord.gg/3qme4XHNKN" target="_blank" rel="noopener">
3
- <img width="124px" src="https://github.com/oauth-xx/oauth2/raw/main/docs/images/logo/galtzo-floss-logos-original.svg?raw=true" alt="Galtzo.com Logo by Aboling0, CC BY-SA 4.0">
4
- </a>
5
- <a href="http://oauth.net/2/" target="_blank" rel="noopener">
6
- <img src="https://github.com/oauth-xx/oauth2/raw/main/docs/images/logo/oauth2-logo-124px.png?raw=true" alt="OAuth 2.0 Logo by Chris Messina, CC BY-SA 3.0">
7
- </a>
8
- <a href="https://www.ruby-lang.org/" target="_blank" rel="noopener">
9
- <img width="124px" src="https://github.com/oauth-xx/oauth2/raw/main/docs/images/logo/ruby-logo-198px.svg?raw=true" alt="Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5">
10
- </a>
11
- </p>
12
-
13
- ## 🔐 OAuth2
14
-
15
- [![Version][👽versioni]][👽version] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![Depfu][🔑depfui♻️]][🔑depfu] [![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] [![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 Caboose is an absolute WAGON][🚎13-cbs-wfi]][🚎13-cbs-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL]
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]
2
+
3
+ [🖼️oauth2-i]: https://logos.galtzo.com/assets/images/oauth/oauth2/avatar-192px.svg
4
+ [🖼️oauth2]: https://github.com/ruby-oauth/oauth2
5
+ [🖼️ruby-lang-i]: https://logos.galtzo.com/assets/images/ruby-lang/avatar-192px.svg
6
+ [🖼️ruby-lang]: https://www.ruby-lang.org/
7
+ [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
8
+ [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
9
+
10
+ # 🔐 OAuth 2.0 Authorization Framework
11
+
12
+ ⭐️ including OAuth 2.1 draft spec & OpenID Connect (OIDC)
13
+
14
+ [![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![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 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 Caboose is an absolute WAGON][🚎13-cbs-wfi]][🚎13-cbs-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL]
15
+
16
+ If ☝️ `ci_badges.map(&:color).detect { it != "green"}` [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
16
17
 
17
18
  ---
18
19
 
19
- [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![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]
20
+ OTOH, if `ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.
21
+
22
+ [![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]
23
+
24
+ ## 🌻 Synopsis
20
25
 
21
26
  OAuth 2.0 is the industry-standard protocol for authorization.
22
27
  OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications,
23
28
  desktop applications, mobile phones, and living room devices.
24
29
  This is a RubyGem for implementing OAuth 2.0 clients (not servers) in Ruby applications.
25
30
 
26
- | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
27
- |-----------------------------------------------|-------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
28
- | 🧪 [oauth-xx/oauth2 on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜wiki] | 🏀 Tiny Matrix | ➖ |
29
- | 🧊 [oauth-xx/oauth2 on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | ➖ | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
30
- | 🐙 [oauth-xx/oauth2 on GitHub][📜src-gh] | A Dirty Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | ➖ | 💯 Full Matrix | ➖ |
31
- | 🤼 [OAuth Ruby Google Group][⛳gg-discussions] | "Active" | ➖ | ➖ | ➖ | ➖ | [💚][⛳gg-discussions] |
32
- | 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |
31
+ ### Quick Example
33
32
 
34
- ### Upgrading Runtime Gem Dependencies
33
+ <details>
34
+ <summary>Convert the following `curl` command into a token request using this gem...</summary>
35
35
 
36
- This project sits underneath a large portion of the authorization systems on the internet.
37
- According to GitHub's project tracking, which I believe only reports on public projects,
38
- [100,000+ projects](https://github.com/oauth-xx/oauth2/network/dependents), and
39
- [500+ packages](https://github.com/oauth-xx/oauth2/network/dependents?dependent_type=PACKAGE) depend on this project.
36
+ ```shell
37
+ curl --request POST \
38
+ --url 'https://login.microsoftonline.com/REDMOND_REDACTED/oauth2/token' \
39
+ --header 'content-type: application/x-www-form-urlencoded' \
40
+ --data grant_type=client_credentials \
41
+ --data client_id=REDMOND_CLIENT_ID \
42
+ --data client_secret=REDMOND_CLIENT_SECRET \
43
+ --data resource=REDMOND_RESOURCE_UUID
44
+ ```
40
45
 
41
- That means it is painful for the Ruby community when this gem forces updates to its runtime dependencies.
46
+ NOTE: In the ruby version below, certain params are passed to the `get_token` call, instead of the client creation.
42
47
 
43
- As a result, great care, and a lot of time, have been invested to ensure this gem is working with all the
44
- leading versions per each minor version of Ruby of all the runtime dependencies it can install with.
48
+ ```ruby
49
+ OAuth2::Client.new(
50
+ "REDMOND_CLIENT_ID", # client_id
51
+ "REDMOND_CLIENT_SECRET", # client_secret
52
+ auth_scheme: :request_body, # Other modes are supported: :basic_auth, :tls_client_auth, :private_key_jwt
53
+ token_url: "oauth2/token", # relative path, except with leading `/`, then absolute path
54
+ site: "https://login.microsoftonline.com/REDMOND_REDACTED",
55
+ ). # The base path for token_url when it is relative
56
+ client_credentials. # There are many other types to choose from!
57
+ get_token(resource: "REDMOND_RESOURCE_UUID")
58
+ ```
45
59
 
46
- What does that mean specifically for the runtime dependencies?
60
+ NOTE: `header` - The content type specified in the `curl` is already the default!
47
61
 
48
- We have 100% test coverage of lines and branches, and this test suite runs across a large matrix
49
- covering the latest patch for each of the following minor versions:
62
+ </details>
50
63
 
64
+ If it seems like you are in the wrong place, you might try one of these:
65
+
66
+ * [OAuth 2.0 Spec][oauth2-spec]
67
+ * [doorkeeper gem][doorkeeper-gem] for OAuth 2.0 server/provider implementation.
68
+ * [oauth sibling gem][sibling-gem] for OAuth 1.0a implementations in Ruby.
69
+
70
+ [oauth2-spec]: https://oauth.net/2/
71
+ [sibling-gem]: https://gitlab.com/ruby-oauth/oauth
72
+ [doorkeeper-gem]: https://github.com/doorkeeper-gem/doorkeeper
73
+
74
+ ## 💡 Info you can shake a stick at
75
+
76
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
77
+ |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
78
+ | 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] |
79
+ | Works with Truffle Ruby | ![Truffle Ruby 22.3 Compat][💎truby-22.3i] ![Truffle Ruby 23.0 Compat][💎truby-23.0i] <br/> [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
80
+ | 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] |
81
+ | 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] |
82
+ | 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] |
83
+ | Documentation | [![Discussion][⛳gg-discussions-img]][⛳gg-discussions] [![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] [![Wiki][📜wiki-img]][📜wiki] |
84
+ | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
85
+ | 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] |
86
+ | Support | [![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] |
87
+ | 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] |
88
+ | `...` 💖 | [![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] |
89
+
90
+ ### Compatibility
91
+
92
+ * Operating Systems: Linux, MacOS, Windows
51
93
  * MRI Ruby @ v2.3, v2.4, v2.5, v2.6, v2.7, v3.0, v3.1, v3.2, v3.3, v3.4, HEAD
52
- * NOTE: This gem will still install on ruby v2.2, but vanilla GitHub Actions no longer supports testing against it, so YMMV.
94
+ * NOTE: This gem will still install on ruby v2.2, but vanilla GitHub Actions no longer supports testing against it, so YMMV.
53
95
  * JRuby @ v9.2, v9.3, v9.4, v10.0, HEAD
54
96
  * TruffleRuby @ v23.1, v24.1, HEAD
55
97
  * gem `faraday` @ v0, v1, v2, HEAD ⏩️ [lostisland/faraday](https://github.com/lostisland/faraday)
@@ -57,33 +99,48 @@ covering the latest patch for each of the following minor versions:
57
99
  * gem `logger` @ v1.2, v1.5, v1.7, HEAD ⏩️ [ruby/logger](https://github.com/ruby/logger)
58
100
  * gem `multi_xml` @ v0.5, v0.6, v0.7, HEAD ⏩️ [sferik/multi_xml](https://github.com/sferik/multi_xml)
59
101
  * gem `rack` @ v1.2, v1.6, v2, v3, HEAD ⏩️ [rack/rack](https://github.com/rack/rack)
60
- * gem `snaky_hash` @ v2, HEAD ⏩️ [oauth-xx/snaky_hash](https://gitlab.com/oauth-xx/snaky_hash)
61
- * gem `version_gem` @ v1, HEAD ⏩️ [oauth-xx/version_gem](https://gitlab.com/oauth-xx/version_gem)
102
+ * gem `snaky_hash` @ v2, HEAD ⏩️ [ruby-oauth/snaky_hash](https://gitlab.com/ruby-oauth/snaky_hash)
103
+ * gem `version_gem` @ v1, HEAD ⏩️ [ruby-oauth/version_gem](https://gitlab.com/ruby-oauth/version_gem)
62
104
 
63
- The last two were extracted from this gem. They are part of the `oauth-xx` org,
105
+ The last two were extracted from this gem. They are part of the `ruby-oauth` org,
64
106
  and are developed in tight collaboration with this gem.
65
107
 
66
108
  Also, where reasonable, tested against the runtime dependencies of those dependencies:
67
109
 
68
110
  * gem `hashie` @ v0, v1, v2, v3, v4, v5, HEAD ⏩️ [hashie/hashie](https://github.com/hashie/hashie)
69
111
 
112
+ #### Upgrading Runtime Gem Dependencies
113
+
114
+ This project sits underneath a large portion of the authorization systems on the internet.
115
+ According to GitHub's project tracking, which I believe only reports on public projects,
116
+ [100,000+ projects](https://github.com/ruby-oauth/oauth2/network/dependents), and
117
+ [500+ packages](https://github.com/ruby-oauth/oauth2/network/dependents?dependent_type=PACKAGE) depend on this project.
118
+
119
+ That means it is painful for the Ruby community when this gem forces updates to its runtime dependencies.
120
+
121
+ As a result, great care, and a lot of time, have been invested to ensure this gem is working with all the
122
+ leading versions per each minor version of Ruby of all the runtime dependencies it can install with.
123
+
124
+ What does that mean specifically for the runtime dependencies?
125
+
126
+ We have 100% test coverage of lines and branches, and this test suite runs across a large matrix
127
+ covering the latest patch for each of the following minor versions:
128
+
129
+ | 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 |
130
+ |------------------------------------------------|--------------------------------------------------------------------------------------|
131
+ | 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2](https://github.com/appraisal-rb/appraisal2) ✨ |
132
+
70
133
  #### You should upgrade this gem with confidence\*.
71
134
 
72
135
  - This gem follows a _strict & correct_ (according to the maintainer of SemVer; [more info][sv-pub-api]) interpretation of SemVer.
73
- - Dropping support for **any** of the runtime dependency versions above will be a major version bump.
74
- - If you aren't on one of the minor versions above, make getting there a priority.
136
+ - Dropping support for **any** of the runtime dependency versions above will be a major version bump.
137
+ - If you aren't on one of the minor versions above, make getting there a priority.
75
138
  - You should upgrade the dependencies of this gem with confidence\*.
76
139
  - Please do upgrade, and then, when it goes smooth as butter [please sponsor me][🖇sponsor]. Thanks!
77
140
 
78
141
  [sv-pub-api]: #-is-platform-support-part-of-the-public-api
79
142
 
80
- \* MIT license; I am unable to make guarantees.
81
-
82
- | 🚚 Test matrix brought to you by | 🔎 appraisal++ |
83
- |----------------------------------|-------------------------------------------------------------------------|
84
- | Adds back support for old Rubies | ✨ [appraisal PR #250](https://github.com/thoughtbot/appraisal/pull/250) |
85
- | Adds support for `eval_gemfile` | ✨ [appraisal PR #248](https://github.com/thoughtbot/appraisal/pull/248) |
86
- | Please review | my PRs! |
143
+ \* MIT license; The only guarantees I make are for [enterprise support](#enterprise-support).
87
144
 
88
145
  <details>
89
146
  <summary>Standard Library Dependencies</summary>
@@ -96,67 +153,49 @@ The various versions of each are tested via the Ruby test matrix, along with wha
96
153
  * time
97
154
  * logger (removed from stdlib in Ruby 3.5 so added as runtime dependency in v2.0.10)
98
155
 
99
- If you use a gem version it should work fine!
156
+ If you use a gem version of a core Ruby library it should work fine!
100
157
 
101
158
  </details>
102
159
 
103
- ### Quick Usage Example for AI and Copy / Pasting
160
+ ### Federated DVCS
104
161
 
105
- Convert the following `curl` command into a token request using this gem...
162
+ <details>
163
+ <summary>Find this repo on other forges (Coming soon!)</summary>
106
164
 
107
- ```shell
108
- curl --request POST \
109
- --url 'https://login.microsoftonline.com/REDMOND_REDACTED/oauth2/token' \
110
- --header 'content-type: application/x-www-form-urlencoded' \
111
- --data grant_type=client_credentials \
112
- --data client_id=REDMOND_CLIENT_ID \
113
- --data client_secret=REDMOND_CLIENT_SECRET \
114
- --data resource=REDMOND_RESOURCE_UUID
115
- ```
165
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
166
+ |-----------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
167
+ | 🧪 [ruby-oauth/oauth2 on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜wiki] | 🏀 Tiny Matrix | ➖ |
168
+ | 🧊 [ruby-oauth/oauth2 on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
169
+ | 🐙 [ruby-oauth/oauth2 on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | ➖ | 💯 Full Matrix | [💚][gh-discussions] |
170
+ | 🤼 [OAuth Ruby Google Group][⛳gg-discussions] | "Active" | ➖ | ➖ | ➖ | ➖ | [💚][⛳gg-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] |
116
172
 
117
- NOTE: In the ruby version below, certain params are passed to the `get_token` call, instead of the client creation.
173
+ </details>
118
174
 
119
- ```ruby
120
- OAuth2::Client.new(
121
- "REDMOND_CLIENT_ID", # client_id
122
- "REDMOND_CLIENT_SECRET", # client_secret
123
- auth_scheme: :request_body, # Other modes are supported: :basic_auth, :tls_client_auth, :private_key_jwt
124
- token_url: "oauth2/token", # relative path, except with leading `/`, then absolute path
125
- site: "https://login.microsoftonline.com/REDMOND_REDACTED",
126
- ). # The base path for token_url when it is relative
127
- client_credentials. # There are many other types to choose from!
128
- get_token(resource: "REDMOND_RESOURCE_UUID")
129
- ```
175
+ [gh-discussions]: https://github.com/ruby-oauth/oauth2/discussions
130
176
 
131
- NOTE: `header` - The content type specified in the `curl` is already the default!
177
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/oauth2)](https://tidelift.com/subscription/pkg/rubygems-oauth2?utm_source=rubygems-oauth2&utm_medium=referral&utm_campaign=readme)
132
178
 
133
- If any of the above makes you uncomfortable, you may be in the wrong place.
134
- One of these might be what you are looking for:
179
+ Available as part of the Tidelift Subscription.
135
180
 
136
- * [OAuth 2.0 Spec][oauth2-spec]
137
- * [doorkeeper gem][doorkeeper-gem] for OAuth 2.0 server/provider implementation.
138
- * [oauth sibling gem][sibling-gem] for OAuth 1.0 implementations in Ruby.
181
+ <details>
182
+ <summary>Need enterprise-level guarantees?</summary>
139
183
 
140
- [oauth2-spec]: https://oauth.net/2/
141
- [sibling-gem]: https://gitlab.com/oauth-xx/oauth
142
- [doorkeeper-gem]: https://github.com/doorkeeper-gem/doorkeeper
184
+ 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.
143
185
 
144
- ## 💡 Info you can shake a stick at
186
+ [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
187
+
188
+ - 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies
189
+ - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
190
+ - 💡Tidelift pays maintainers to maintain the software you depend on!<br/>📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers
191
+
192
+ Alternatively:
193
+
194
+ - [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
195
+ - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
196
+ - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
145
197
 
146
- | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
147
- |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
148
- | Works with JRuby | [![JRuby 9.2 Compat][💎jruby-9.2i]][🚎10-j-wf] [![JRuby 9.3 Compat][💎jruby-9.3i]][🚎10-j-wf] [![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] |
149
- | Works with Truffle Ruby | [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] [![Truffle Ruby HEAD Compat][💎truby-headi]][🚎3-hd-wf] |
150
- | 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] |
151
- | Works with MRI Ruby 2 | [![Ruby 2.3 Compat][💎ruby-2.3i]][🚎13-cbs-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] |
152
- | 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] |
153
- | Documentation | [![Discussion][⛳gg-discussions-img]][⛳gg-discussions] [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![HEAD on RubyDoc.info][📜docs-head-rd-img]][🚎yard-head] [![BDFL Blog][🚂bdfl-blog-img]][🚂bdfl-blog] [![Wiki][📜wiki-img]][📜wiki] |
154
- | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
155
- | Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] |
156
- | Support | [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
157
- | Enterprise Support | [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]<br/>💡Subscribe for support guarantees covering _all_ FLOSS dependencies!<br/>💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]!<br/>💡Tidelift pays maintainers to maintain the software you depend on!<br/>📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers! |
158
- | Comrade BDFL 🎖️ | [![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 BDFL][🚂bdfl-contact-img]][🚂bdfl-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |
159
- | `...` 💖 | [![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] |
198
+ </details>
160
199
 
161
200
  ## 🚀 Release Documentation
162
201
 
@@ -167,6 +206,7 @@ One of these might be what you are looking for:
167
206
 
168
207
  | Version | Release Date | CHANGELOG | README |
169
208
  |---------|--------------|---------------------------------------|---------------------------------|
209
+ | 2.0.13 | 2025-08-30 | [v2.0.13 CHANGELOG][2.0.13-changelog] | [v2.0.13 README][2.0.13-readme] |
170
210
  | 2.0.12 | 2025-05-31 | [v2.0.12 CHANGELOG][2.0.12-changelog] | [v2.0.12 README][2.0.12-readme] |
171
211
  | 2.0.11 | 2025-05-23 | [v2.0.11 CHANGELOG][2.0.11-changelog] | [v2.0.11 README][2.0.11-readme] |
172
212
  | 2.0.10 | 2025-05-17 | [v2.0.10 CHANGELOG][2.0.10-changelog] | [v2.0.10 README][2.0.10-readme] |
@@ -180,35 +220,38 @@ One of these might be what you are looking for:
180
220
  | 2.0.2 | 2022-06-24 | [v2.0.2 CHANGELOG][2.0.2-changelog] | [v2.0.2 README][2.0.2-readme] |
181
221
  | 2.0.1 | 2022-06-22 | [v2.0.1 CHANGELOG][2.0.1-changelog] | [v2.0.1 README][2.0.1-readme] |
182
222
  | 2.0.0 | 2022-06-21 | [v2.0.0 CHANGELOG][2.0.0-changelog] | [v2.0.0 README][2.0.0-readme] |
223
+
183
224
  </details>
184
225
 
185
- [2.0.12-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2012---2025-05-31
186
- [2.0.11-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2011---2025-05-23
187
- [2.0.10-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2010---2025-05-17
188
- [2.0.9-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#209---2022-09-16
189
- [2.0.8-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#208---2022-09-01
190
- [2.0.7-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#207---2022-08-22
191
- [2.0.6-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#206---2022-07-13
192
- [2.0.5-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#205---2022-07-07
193
- [2.0.4-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#204---2022-07-01
194
- [2.0.3-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#203---2022-06-28
195
- [2.0.2-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#202---2022-06-24
196
- [2.0.1-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#201---2022-06-22
197
- [2.0.0-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#200---2022-06-21
198
-
199
- [2.0.12-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.12/README.md
200
- [2.0.11-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.11/README.md
201
- [2.0.10-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.10/README.md
202
- [2.0.9-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.9/README.md
203
- [2.0.8-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.8/README.md
204
- [2.0.7-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.7/README.md
205
- [2.0.6-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.6/README.md
206
- [2.0.5-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.5/README.md
207
- [2.0.4-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.4/README.md
208
- [2.0.3-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.3/README.md
209
- [2.0.2-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.2/README.md
210
- [2.0.1-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.1/README.md
211
- [2.0.0-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v2.0.0/README.md
226
+ [2.0.13-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2013---2025-08-30
227
+ [2.0.12-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2012---2025-05-31
228
+ [2.0.11-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2011---2025-05-23
229
+ [2.0.10-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#2010---2025-05-17
230
+ [2.0.9-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#209---2022-09-16
231
+ [2.0.8-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#208---2022-09-01
232
+ [2.0.7-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#207---2022-08-22
233
+ [2.0.6-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#206---2022-07-13
234
+ [2.0.5-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#205---2022-07-07
235
+ [2.0.4-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#204---2022-07-01
236
+ [2.0.3-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#203---2022-06-28
237
+ [2.0.2-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#202---2022-06-24
238
+ [2.0.1-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#201---2022-06-22
239
+ [2.0.0-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#200---2022-06-21
240
+
241
+ [2.0.13-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.13/README.md
242
+ [2.0.12-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.12/README.md
243
+ [2.0.11-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.11/README.md
244
+ [2.0.10-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.10/README.md
245
+ [2.0.9-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.9/README.md
246
+ [2.0.8-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.8/README.md
247
+ [2.0.7-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.7/README.md
248
+ [2.0.6-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.6/README.md
249
+ [2.0.5-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.5/README.md
250
+ [2.0.4-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.4/README.md
251
+ [2.0.3-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.3/README.md
252
+ [2.0.2-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.2/README.md
253
+ [2.0.1-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.1/README.md
254
+ [2.0.0-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v2.0.0/README.md
212
255
 
213
256
  ### Older Releases
214
257
 
@@ -231,77 +274,86 @@ One of these might be what you are looking for:
231
274
  | 1.4.0 | Jun 9, 2017 | [v1.4.0 CHANGELOG][1.4.0-changelog] | [v1.4.0 README][1.4.0-readme] |
232
275
  </details>
233
276
 
234
- [1.4.11-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#1411---2022-09-16
235
- [1.4.10-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#1410---2022-07-01
236
- [1.4.9-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#149---2022-02-20
237
- [1.4.8-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#148---2022-02-18
238
- [1.4.7-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#147---2021-03-19
239
- [1.4.6-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#146---2021-03-19
240
- [1.4.5-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#145---2021-03-18
241
- [1.4.4-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#144---2020-02-12
242
- [1.4.3-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#143---2020-01-29
243
- [1.4.2-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#142---2019-10-01
244
- [1.4.1-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#141---2018-10-13
245
- [1.4.0-changelog]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#140---2017-06-09
246
-
247
- [1.4.11-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.11/README.md
248
- [1.4.10-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.10/README.md
249
- [1.4.9-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.9/README.md
250
- [1.4.8-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.8/README.md
251
- [1.4.7-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.7/README.md
252
- [1.4.6-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.6/README.md
253
- [1.4.5-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.5/README.md
254
- [1.4.4-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.4/README.md
255
- [1.4.3-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.3/README.md
256
- [1.4.2-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.2/README.md
257
- [1.4.1-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.1/README.md
258
- [1.4.0-readme]: https://gitlab.com/oauth-xx/oauth2/-/blob/v1.4.0/README.md
277
+ [1.4.11-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#1411---2022-09-16
278
+ [1.4.10-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#1410---2022-07-01
279
+ [1.4.9-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#149---2022-02-20
280
+ [1.4.8-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#148---2022-02-18
281
+ [1.4.7-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#147---2021-03-19
282
+ [1.4.6-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#146---2021-03-19
283
+ [1.4.5-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#145---2021-03-18
284
+ [1.4.4-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#144---2020-02-12
285
+ [1.4.3-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#143---2020-01-29
286
+ [1.4.2-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#142---2019-10-01
287
+ [1.4.1-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#141---2018-10-13
288
+ [1.4.0-changelog]: https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md?ref_type=heads#140---2017-06-09
289
+
290
+ [1.4.11-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.11/README.md
291
+ [1.4.10-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.10/README.md
292
+ [1.4.9-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.9/README.md
293
+ [1.4.8-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.8/README.md
294
+ [1.4.7-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.7/README.md
295
+ [1.4.6-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.6/README.md
296
+ [1.4.5-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.5/README.md
297
+ [1.4.4-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.4/README.md
298
+ [1.4.3-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.3/README.md
299
+ [1.4.2-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.2/README.md
300
+ [1.4.1-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.1/README.md
301
+ [1.4.0-readme]: https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.4.0/README.md
259
302
 
260
303
  <details>
261
304
  <summary>1.3.x Readmes</summary>
262
305
 
263
- | Version | Release Date | Readme |
264
- |----------|--------------|----------------------------------------------------------|
265
- | 1.3.1 | Mar 3, 2017 | https://gitlab.com/oauth-xx/oauth2/-/blob/v1.3.1/README.md |
266
- | 1.3.0 | Dec 27, 2016 | https://gitlab.com/oauth-xx/oauth2/-/blob/v1.3.0/README.md |
306
+ | Version | Release Date | Readme |
307
+ |---------|--------------|--------------------------------------------------------------|
308
+ | 1.3.1 | Mar 3, 2017 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.3.1/README.md |
309
+ | 1.3.0 | Dec 27, 2016 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.3.0/README.md |
310
+
267
311
  </details>
268
312
 
269
313
  <details>
270
314
  <summary>&le;= 1.2.x Readmes (2016 and before)</summary>
271
315
 
272
- | Version | Release Date | Readme |
273
- |----------|--------------|----------------------------------------------------------|
274
- | 1.2.0 | Jun 30, 2016 | https://gitlab.com/oauth-xx/oauth2/-/blob/v1.2.0/README.md |
275
- | 1.1.0 | Jan 30, 2016 | https://gitlab.com/oauth-xx/oauth2/-/blob/v1.1.0/README.md |
276
- | 1.0.0 | May 23, 2014 | https://gitlab.com/oauth-xx/oauth2/-/blob/v1.0.0/README.md |
277
- | < 1.0.0 | Find here | https://gitlab.com/oauth-xx/oauth2/-/tags |
316
+ | Version | Release Date | Readme |
317
+ |---------|--------------|--------------------------------------------------------------|
318
+ | 1.2.0 | Jun 30, 2016 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.2.0/README.md |
319
+ | 1.1.0 | Jan 30, 2016 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.1.0/README.md |
320
+ | 1.0.0 | May 23, 2014 | https://gitlab.com/ruby-oauth/oauth2/-/blob/v1.0.0/README.md |
321
+ | < 1.0.0 | Find here | https://gitlab.com/ruby-oauth/oauth2/-/tags |
322
+
278
323
  </details>
279
324
 
280
325
  ## ✨ Installation
281
326
 
282
327
  Install the gem and add to the application's Gemfile by executing:
283
328
 
284
- $ bundle add oauth2
329
+ ```console
330
+ bundle add oauth2
331
+ ```
285
332
 
286
333
  If bundler is not being used to manage dependencies, install the gem by executing:
287
334
 
288
- $ gem install oauth2
335
+ ```console
336
+ gem install oauth2
337
+ ```
289
338
 
290
339
  ### 🔒 Secure Installation
291
340
 
292
- `oauth2` is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
341
+ <details>
342
+ <summary>For Medium or High Security Installations</summary>
343
+
344
+ This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
293
345
  [stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
294
346
  by following the instructions below.
295
347
 
296
348
  Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
297
349
 
298
- ```shell
299
- gem cert --add <(curl -Ls https://raw.github.com/oauth-xx/oauth2/main/certs/pboling.pem)
350
+ ```console
351
+ gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
300
352
  ```
301
353
 
302
354
  You only need to do that once. Then proceed to install with:
303
355
 
304
- ```shell
356
+ ```console
305
357
  gem install oauth2 -P MediumSecurity
306
358
  ```
307
359
 
@@ -311,37 +363,24 @@ This is necessary because not all of `oauth2`’s dependencies are signed, so we
311
363
 
312
364
  If you want to up your security game full-time:
313
365
 
314
- ```shell
366
+ ```console
315
367
  bundle config set --global trust-policy MediumSecurity
316
368
  ```
317
369
 
318
370
  NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.
319
371
 
320
- ## OAuth2 for Enterprise
321
-
322
- Available as part of the Tidelift Subscription.
323
-
324
- 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. [Learn more.][tidelift-ref]
325
-
326
- [tidelift-ref]: https://tidelift.com/subscription/pkg/rubygems-oauth2?utm_source=rubygems-oauth2&utm_medium=referral&utm_campaign=enterprise
327
-
328
- ## Security contact information
329
-
330
- To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
331
- Tidelift will coordinate the fix and disclosure.
332
-
333
- For more see [SECURITY.md][🔐security].
372
+ </details>
334
373
 
335
374
  ## What is new for v2.0?
336
375
 
337
376
  - Works with Ruby versions >= 2.2
338
377
  - Drop support for the expired MAC Draft (all versions)
339
378
  - Support IETF rfc7515 JSON Web Signature - JWS (since v2.0.12)
340
- - Support JWT `kid` for key discovery and management
379
+ - Support JWT `kid` for key discovery and management
341
380
  - Support IETF rfc7523 JWT Bearer Tokens (since v2.0.0)
342
381
  - Support IETF rfc7231 Relative Location in Redirect (since v2.0.0)
343
382
  - Support IETF rfc6749 Don't set oauth params when nil (since v2.0.0)
344
- - Support IETF rfc7009 Token Revocation (since v2.0.10)
383
+ - Support IETF rfc7009 Token Revocation (since v2.0.10, updated in v2.0.13 to support revocation via URL-encoded parameters)
345
384
  - 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)
346
385
  - 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`
347
386
  - Adds option to `OAuth2::Client#get_token`:
@@ -349,14 +388,14 @@ For more see [SECURITY.md][🔐security].
349
388
  - Adds option to `OAuth2::AccessToken#initialize`:
350
389
  - `:expires_latency` (`nil`); number of seconds by which AccessToken validity will be reduced to offset latency
351
390
  - By default, keys are transformed to snake case.
352
- - Original keys will still work as previously, in most scenarios, thanks to [snaky_hash][snaky_hash] gem.
353
- - 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.
354
- - As of version 2.0.4 you can turn key transformation off with the `snaky: false` option.
391
+ - Original keys will still work as previously, in most scenarios, thanks to [snaky_hash][snaky_hash] gem.
392
+ - 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.
393
+ - As of version 2.0.4 you can turn key transformation off with the `snaky: false` option.
355
394
  - By default, the `:auth_scheme` is now `:basic_auth` (instead of `:request_body`)
356
- - Third-party strategies and gems may need to be updated if a provider was requiring client id/secret in the request body
357
- - [... A lot more](https://gitlab.com/oauth-xx/oauth2/-/blob/main/CHANGELOG.md#200-2022-06-21-tag)
395
+ - Third-party strategies and gems may need to be updated if a provider was requiring client id/secret in the request body
396
+ - [... A lot more](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/CHANGELOG.md#200-2022-06-21-tag)
358
397
 
359
- [snaky_hash]: https://gitlab.com/oauth-xx/snaky_hash
398
+ [snaky_hash]: https://gitlab.com/ruby-oauth/snaky_hash
360
399
 
361
400
  ## Compatibility
362
401
 
@@ -372,7 +411,7 @@ This gem is tested against MRI, JRuby, and Truffleruby.
372
411
  Each of those has varying versions that target a specific version of MRI Ruby.
373
412
  This gem should work in the just-listed Ruby engines according to the targeted MRI compatibility in the table below.
374
413
  If you would like to add support for additional engines,
375
- see [gemfiles/README.md](gemfiles/README.md), then submit a PR to the correct maintenance branch as according to the table below.
414
+ see [gemfiles/README.md](gemfiles/README.md), then submit a PR to the correct maintenance branch as according to the table below.
376
415
  </details>
377
416
 
378
417
  <details>
@@ -401,9 +440,7 @@ of a major release, support for that Ruby version may be dropped.
401
440
  NOTE: The 1.4 series will only receive critical security updates.
402
441
  See [SECURITY.md][🔐security].
403
442
 
404
- ## 🔧 Basic Usage
405
-
406
- ### Global Configuration
443
+ ## ⚙️ Configuration
407
444
 
408
445
  You can turn on additional warnings.
409
446
 
@@ -430,6 +467,8 @@ You'll likely need to do some source diving.
430
467
  This gem has 100% test coverage for lines and branches, so the specs are a great place to look for ideas.
431
468
  If you have time and energy please contribute to the documentation!
432
469
 
470
+ ## 🔧 Basic Usage
471
+
433
472
  ### `authorize_url` and `token_url` are on site root (Just Works!)
434
473
 
435
474
  ```ruby
@@ -495,32 +534,38 @@ As of v2.0.11, if you need to serialize the parsed result, you can!
495
534
 
496
535
  There are two ways to do this, globally, or discretely. The discrete way is recommended.
497
536
 
498
- 1. Globally configure `SnakyHash::StringKeyed` to use the serializer. Put this in your code somewhere reasonable (like an initializer for Rails):
537
+ ##### Global Serialization Config
538
+
539
+ Globally configure `SnakyHash::StringKeyed` to use the serializer. Put this in your code somewhere reasonable (like an initializer for Rails).
499
540
 
500
- ```ruby
541
+ ```ruby
501
542
  SnakyHash::StringKeyed.class_eval do
502
543
  extend SnakyHash::Serializer
503
544
  end
504
- ```
545
+ ```
546
+
547
+ ##### Discrete Serialization Config
505
548
 
506
- 2. Discretely configure a custom Snaky Hash class to use the serializer:
549
+ Discretely configure a custom Snaky Hash class to use the serializer.
507
550
 
508
- ```ruby
551
+ ```ruby
509
552
  class MySnakyHash < SnakyHash::StringKeyed
510
553
  # Give this hash class `dump` and `load` abilities!
511
554
  extend SnakyHash::Serializer
512
555
  end
513
556
 
514
- # And tell your client to use the custom class in each call:
557
+ # And tell your client to use the custom class in each call:
515
558
  client = OAuth2::Client.new("client_id", "client_secret", site: "https://example.org/oauth2")
516
559
  token = client.get_token({snaky_hash_klass: MySnakyHash})
517
- ```
560
+ ```
518
561
 
519
562
  ##### Serialization Extensions
520
563
 
564
+ These extensions work regardless of whether you used the global or discrete config above.
565
+
521
566
  There are a few hacks you may need in your class to support Ruby < 2.4.2 or < 2.6.
522
567
  They are likely not needed if you are on a newer Ruby.
523
- See `response_spec.rb` if you need to study the hacks for older Rubies.
568
+ 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.
524
569
 
525
570
  ```ruby
526
571
  class MySnakyHash < SnakyHash::StringKeyed
@@ -576,9 +621,9 @@ class MySnakyHash < SnakyHash::StringKeyed
576
621
  end
577
622
  ```
578
623
 
579
- See `response_spec.rb`, or the [oauth-xx/snaky_hash](https://gitlab.com/oauth-xx/snaky_hash) gem for more ideas.
624
+ See [response_spec.rb](https://github.com/ruby-oauth/oauth2/blob/main/spec/oauth2/response_spec.rb), or the [ruby-oauth/snaky_hash](https://gitlab.com/ruby-oauth/snaky_hash) gem for more ideas.
580
625
 
581
- #### What if I hate snakes and/or indifference?
626
+ #### Prefer camelCase over snake_case? => snaky: false
582
627
 
583
628
  ```ruby
584
629
  response = access.get("/api/resource", params: {"query_foo" => "bar"}, snaky: false)
@@ -619,7 +664,7 @@ The `AccessToken` methods `#get`, `#post`, `#put` and `#delete` and the generic
619
664
  will return an instance of the #OAuth2::Response class.
620
665
 
621
666
  This instance contains a `#parsed` method that will parse the response body and
622
- return a Hash-like [`SnakyHash::StringKeyed`](https://gitlab.com/oauth-xx/snaky_hash/-/blob/main/lib/snaky_hash/string_keyed.rb) if the `Content-Type` is `application/x-www-form-urlencoded` or if
667
+ return a Hash-like [`SnakyHash::StringKeyed`](https://gitlab.com/ruby-oauth/snaky_hash/-/blob/main/lib/snaky_hash/string_keyed.rb) if the `Content-Type` is `application/x-www-form-urlencoded` or if
623
668
  the body is a JSON object. It will return an Array if the body is a JSON
624
669
  array. Otherwise, it will return the original body string.
625
670
 
@@ -647,13 +692,29 @@ Response instance will contain the `OAuth2::Error` instance.
647
692
 
648
693
  ### Authorization Grants
649
694
 
695
+ Note on OAuth 2.1 (draft):
696
+ - 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.
697
+ - Redirect URIs must be compared using exact string matching by the Authorization Server.
698
+ - 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.
699
+ - Bearer tokens in the query string are omitted due to security risks; prefer Authorization header usage.
700
+ - Refresh tokens for public clients must either be sender-constrained (e.g., DPoP/MTLS) or one-time use.
701
+ - The definitions of public and confidential clients are simplified to refer only to whether the client has credentials.
702
+
703
+ References:
704
+ - OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
705
+ - Aaron Parecki: https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1
706
+ - FusionAuth: https://fusionauth.io/blog/2020/04/15/whats-new-in-oauth-2-1
707
+ - Okta: https://developer.okta.com/blog/2019/12/13/oauth-2-1-how-many-rfcs
708
+ - Video: https://www.youtube.com/watch?v=g_aVPdwBTfw
709
+ - Differences overview: https://fusionauth.io/learn/expert-advice/oauth/differences-between-oauth-2-oauth-2-1/
710
+
650
711
  Currently, the Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials, and Assertion
651
712
  authentication grant types have helper strategy classes that simplify client
652
- use. They are available via the [`#auth_code`](https://gitlab.com/oauth-xx/oauth2/-/blob/main/lib/oauth2/strategy/auth_code.rb),
653
- [`#implicit`](https://gitlab.com/oauth-xx/oauth2/-/blob/main/lib/oauth2/strategy/implicit.rb),
654
- [`#password`](https://gitlab.com/oauth-xx/oauth2/-/blob/main/lib/oauth2/strategy/password.rb),
655
- [`#client_credentials`](https://gitlab.com/oauth-xx/oauth2/-/blob/main/lib/oauth2/strategy/client_credentials.rb), and
656
- [`#assertion`](https://gitlab.com/oauth-xx/oauth2/-/blob/main/lib/oauth2/strategy/assertion.rb) methods respectively.
713
+ use. They are available via the [`#auth_code`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/auth_code.rb),
714
+ [`#implicit`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/implicit.rb),
715
+ [`#password`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/password.rb),
716
+ [`#client_credentials`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/client_credentials.rb), and
717
+ [`#assertion`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/assertion.rb) methods respectively.
657
718
 
658
719
  These aren't full examples, but demonstrative of the differences between usage for each strategy.
659
720
  ```ruby
@@ -694,14 +755,414 @@ access = client.auth_code.get_token("code_value", redirect_uri: "http://localhos
694
755
  You can always use the `#request` method on the `OAuth2::Client` instance to make
695
756
  requests for tokens for any Authentication grant type.
696
757
 
758
+ ## 📘 Comprehensive Usage
759
+
760
+ ### Common Flows (end-to-end)
761
+
762
+ - Authorization Code (server-side web app):
763
+
764
+ ```ruby
765
+ require "oauth2"
766
+ client = OAuth2::Client.new(
767
+ ENV["CLIENT_ID"],
768
+ ENV["CLIENT_SECRET"],
769
+ site: "https://provider.example.com",
770
+ redirect_uri: "https://my.app.example.com/oauth/callback",
771
+ )
772
+
773
+ # Step 1: redirect user to consent
774
+ state = SecureRandom.hex(16)
775
+ auth_url = client.auth_code.authorize_url(scope: "openid profile email", state: state)
776
+ # redirect_to auth_url
777
+
778
+ # Step 2: handle the callback
779
+ # params[:code], params[:state]
780
+ raise "state mismatch" unless params[:state] == state
781
+ access = client.auth_code.get_token(params[:code])
782
+
783
+ # Step 3: call APIs
784
+ profile = access.get("/api/v1/me").parsed
785
+ ```
786
+
787
+ - Client Credentials (machine-to-machine):
788
+
789
+ ```ruby
790
+ client = OAuth2::Client.new(ENV["CLIENT_ID"], ENV["CLIENT_SECRET"], site: "https://provider.example.com")
791
+ access = client.client_credentials.get_token(audience: "https://api.example.com")
792
+ resp = access.get("/v1/things")
793
+ ```
794
+
795
+ - Resource Owner Password (legacy; avoid when possible):
796
+
797
+ ```ruby
798
+ access = client.password.get_token("jdoe", "s3cret", scope: "read")
799
+ ```
800
+
801
+ #### Examples
802
+
803
+ <details>
804
+ <summary>JHipster UAA (Spring Cloud) password grant example (legacy; avoid when possible)</summary>
805
+
806
+ ```ruby
807
+ # This converts a Postman/Net::HTTP multipart token request to oauth2 gem usage.
808
+ # JHipster UAA typically exposes the token endpoint at /uaa/oauth/token.
809
+ # The original snippet included:
810
+ # - Basic Authorization header for the client (web_app:changeit)
811
+ # - X-XSRF-TOKEN header from a cookie (some deployments require it)
812
+ # - grant_type=password with username/password and client_id
813
+ # Using oauth2 gem, you don't need to build multipart bodies; the gem sends
814
+ # application/x-www-form-urlencoded as required by RFC 6749.
815
+
816
+ require "oauth2"
817
+
818
+ client = OAuth2::Client.new(
819
+ "web_app", # client_id
820
+ "changeit", # client_secret
821
+ site: "http://localhost:8080/uaa",
822
+ token_url: "/oauth/token", # absolute under site (or "oauth/token" relative)
823
+ auth_scheme: :basic_auth, # sends HTTP Basic Authorization header
824
+ )
825
+
826
+ # If your UAA requires an XSRF header for the token call, provide it as a header.
827
+ # Often this is not required for token endpoints, but if your gateway enforces it,
828
+ # obtain the value from the XSRF-TOKEN cookie and pass it here.
829
+ xsrf_token = ENV["X_XSRF_TOKEN"] # e.g., pulled from a prior set-cookie value
830
+
831
+ access = client.password.get_token(
832
+ "admin", # username
833
+ "admin", # password
834
+ headers: xsrf_token ? {"X-XSRF-TOKEN" => xsrf_token} : {},
835
+ # JHipster commonly also accepts/needs the client_id in the body; include if required:
836
+ # client_id: "web_app",
837
+ )
838
+
839
+ puts access.token
840
+ puts access.to_hash # full token response
841
+ ```
842
+
843
+ Notes:
844
+ - Resource Owner Password Credentials (ROPC) is deprecated in OAuth 2.1 and discouraged. Prefer Authorization Code + PKCE.
845
+ - 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.
846
+ - For Basic auth, auth_scheme: :basic_auth handles the Authorization header; you do not need to base64-encode manually.
847
+
848
+ </details>
849
+
850
+ ### Refresh Tokens
851
+
852
+ When the server issues a refresh_token, you can refresh manually or implement an auto-refresh wrapper.
853
+
854
+ - Manual refresh:
855
+
856
+ ```ruby
857
+ if access.expired?
858
+ access = access.refresh
859
+ end
860
+ ```
861
+
862
+ - Auto-refresh wrapper pattern:
863
+
864
+ ```ruby
865
+ class AutoRefreshingToken
866
+ def initialize(token_provider, store: nil)
867
+ @token = token_provider
868
+ @store = store # e.g., something that responds to read/write for token data
869
+ end
870
+
871
+ def with(&blk)
872
+ tok = ensure_fresh!
873
+ blk ? blk.call(tok) : tok
874
+ rescue OAuth2::Error => e
875
+ # If a 401 suggests token invalidation, try one refresh and retry once
876
+ if e.response && e.response.status == 401 && @token.refresh_token
877
+ @token = @token.refresh
878
+ @store.write(@token.to_hash) if @store
879
+ retry
880
+ end
881
+ raise
882
+ end
883
+
884
+ private
885
+
886
+ def ensure_fresh!
887
+ if @token.expired? && @token.refresh_token
888
+ @token = @token.refresh
889
+ @store.write(@token.to_hash) if @store
890
+ end
891
+ @token
892
+ end
893
+ end
894
+
895
+ # usage
896
+ keeper = AutoRefreshingToken.new(access)
897
+ keeper.with { |tok| tok.get("/v1/protected") }
898
+ ```
899
+
900
+ Persist the token across processes using `AccessToken#to_hash` and `AccessToken.from_hash(client, hash)`.
901
+
902
+ ### Token Revocation (RFC 7009)
903
+
904
+ You can revoke either the access token or the refresh token.
905
+
906
+ ```ruby
907
+ # Revoke the current access token
908
+ access.revoke(token_type_hint: :access_token)
909
+
910
+ # Or explicitly revoke the refresh token (often also invalidates associated access tokens)
911
+ access.revoke(token_type_hint: :refresh_token)
912
+ ```
913
+
914
+ ### Client Configuration Tips
915
+
916
+ #### Mutual TLS (mTLS) client authentication
917
+
918
+ 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.
919
+
920
+ Example using PEM files (certificate and key):
921
+
922
+ ```ruby
923
+ require "oauth2"
924
+ require "openssl"
925
+
926
+ client = OAuth2::Client.new(
927
+ ENV.fetch("CLIENT_ID"),
928
+ ENV.fetch("CLIENT_SECRET"),
929
+ site: "https://example.com",
930
+ authorize_url: "/oauth/authorize/",
931
+ token_url: "/oauth/token/",
932
+ auth_scheme: :tls_client_auth, # if your AS requires mTLS-based client authentication
933
+ connection_opts: {
934
+ ssl: {
935
+ client_cert: OpenSSL::X509::Certificate.new(File.read("localhost.pem")),
936
+ client_key: OpenSSL::PKey::RSA.new(File.read("localhost-key.pem")),
937
+ # Optional extras, uncomment as needed:
938
+ # ca_file: "/path/to/ca-bundle.pem", # custom CA(s)
939
+ # verify: true # enable server cert verification (recommended)
940
+ },
941
+ },
942
+ )
943
+
944
+ # Example token request (any grant type can be used). The mTLS handshake
945
+ # will occur automatically on HTTPS calls using the configured cert/key.
946
+ access = client.client_credentials.get_token
947
+
948
+ # Subsequent resource requests will also use mTLS on HTTPS endpoints of `site`:
949
+ resp = access.get("/v1/protected")
950
+ ```
951
+
952
+ Notes:
953
+ - 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"]).
954
+ - If your certificate and key are in a PKCS#12/PFX bundle, you can load them like:
955
+ - p12 = OpenSSL::PKCS12.new(File.read("client.p12"), ENV["P12_PASSWORD"])
956
+ - client_cert = p12.certificate; client_key = p12.key
957
+ - Server trust:
958
+ - If your environment does not have system CAs, specify ca_file or ca_path inside the ssl: hash.
959
+ - Keep verify: true in production. Set verify: false only for local testing.
960
+ - Faraday adapter: Any adapter that supports Ruby’s OpenSSL should work. net_http (default) and net_http_persistent are common choices.
961
+ - 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).
962
+ - 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.
963
+
964
+ #### Authentication schemes for the token request
965
+
966
+ ```ruby
967
+ OAuth2::Client.new(
968
+ id,
969
+ secret,
970
+ site: "https://provider.example.com",
971
+ auth_scheme: :basic_auth, # default. Alternatives: :request_body, :tls_client_auth, :private_key_jwt
972
+ )
973
+ ```
974
+
975
+ #### Faraday connection, timeouts, proxy, custom adapter/middleware:
976
+
977
+ ```ruby
978
+ client = OAuth2::Client.new(
979
+ id,
980
+ secret,
981
+ site: "https://provider.example.com",
982
+ connection_opts: {
983
+ request: {open_timeout: 5, timeout: 15},
984
+ proxy: ENV["HTTPS_PROXY"],
985
+ ssl: {verify: true},
986
+ },
987
+ ) do |faraday|
988
+ faraday.request(:url_encoded)
989
+ # faraday.response :logger, Logger.new($stdout) # see OAUTH_DEBUG below
990
+ faraday.adapter(:net_http_persistent) # or any Faraday adapter you need
991
+ end
992
+ ```
993
+
994
+ ##### Using flat query params (Faraday::FlatParamsEncoder)
995
+
996
+ 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.
997
+
998
+ ```ruby
999
+ require "faraday"
1000
+
1001
+ client = OAuth2::Client.new(
1002
+ id,
1003
+ secret,
1004
+ site: "https://api.example.com",
1005
+ # Pass Faraday connection options to make FlatParamsEncoder the default
1006
+ connection_opts: {
1007
+ request: {params_encoder: Faraday::FlatParamsEncoder},
1008
+ },
1009
+ ) do |faraday|
1010
+ faraday.request(:url_encoded)
1011
+ faraday.adapter(:net_http)
1012
+ end
1013
+
1014
+ access = client.client_credentials.get_token
1015
+
1016
+ # Example of a GET with two flat filter params (not an array):
1017
+ # Results in: ?filter=order.clientCreatedTime%3E1445006997000&filter=order.clientCreatedTime%3C1445611797000
1018
+ resp = access.get(
1019
+ "/v1/orders",
1020
+ params: {
1021
+ # Provide the values as an array; FlatParamsEncoder expands them as repeated keys
1022
+ filter: [
1023
+ "order.clientCreatedTime>1445006997000",
1024
+ "order.clientCreatedTime<1445611797000",
1025
+ ],
1026
+ },
1027
+ )
1028
+ ```
1029
+
1030
+ If you instead need to build a raw Faraday connection yourself, the equivalent configuration is:
1031
+
1032
+ ```ruby
1033
+ conn = Faraday.new("https://api.example.com", request: {params_encoder: Faraday::FlatParamsEncoder})
1034
+ ```
1035
+
1036
+ #### Redirection
1037
+
1038
+ The library follows up to `max_redirects` (default 5).
1039
+ You can override per-client via `options[:max_redirects]`.
1040
+
1041
+ ### Handling Responses and Errors
1042
+
1043
+ - Parsing:
1044
+
1045
+ ```ruby
1046
+ resp = access.get("/v1/thing")
1047
+ resp.status # Integer
1048
+ resp.headers # Hash
1049
+ resp.body # String
1050
+ resp.parsed # SnakyHash::StringKeyed or Array when JSON array
1051
+ ```
1052
+
1053
+ - Error handling:
1054
+
1055
+ ```ruby
1056
+ begin
1057
+ access.get("/v1/forbidden")
1058
+ rescue OAuth2::Error => e
1059
+ e.code # OAuth2 error code (when present)
1060
+ e.description # OAuth2 error description (when present)
1061
+ e.response # OAuth2::Response (full access to status/headers/body)
1062
+ end
1063
+ ```
1064
+
1065
+ - Disable raising on 4xx/5xx to inspect the response yourself:
1066
+
1067
+ ```ruby
1068
+ client = OAuth2::Client.new(id, secret, site: site, raise_errors: false)
1069
+ res = client.request(:get, "/v1/maybe-errors")
1070
+ if res.status == 429
1071
+ sleep res.headers["retry-after"].to_i
1072
+ end
1073
+ ```
1074
+
1075
+ ### Making Raw Token Requests
1076
+
1077
+ If a provider requires non-standard parameters or headers, you can call `client.get_token` directly:
1078
+
1079
+ ```ruby
1080
+ access = client.get_token({
1081
+ grant_type: "client_credentials",
1082
+ audience: "https://api.example.com",
1083
+ headers: {"X-Custom" => "value"},
1084
+ parse: :json, # override parsing
1085
+ })
1086
+ ```
1087
+
1088
+ ### OpenID Connect (OIDC) Notes
1089
+
1090
+ - If the token response includes an `id_token` (a JWT), this gem surfaces it but does not validate the signature. Use a JWT library and your provider's JWKs to verify it.
1091
+ - For private_key_jwt client authentication, provide `auth_scheme: :private_key_jwt` and ensure your key configuration matches the provider requirements.
1092
+ - See [OIDC.md](OIDC.md) for a more complete OIDC overview, example, and links to the relevant specifications.
1093
+
1094
+ ### Debugging
1095
+
1096
+ - Set environment variable `OAUTH_DEBUG=true` to enable verbose Faraday logging (uses the client-provided logger).
1097
+ - 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.
1098
+
1099
+ ---
1100
+
1101
+ ## 🦷 FLOSS Funding
1102
+
1103
+ While ruby-oauth tools are free software and will always be, the project would benefit immensely from some funding.
1104
+ Raising a monthly budget of... "dollars" would make the project more sustainable.
1105
+
1106
+ We welcome both individual and corporate sponsors! We also offer a
1107
+ wide array of funding channels to account for your preferences
1108
+ (although currently [Open Collective][🖇osc] is our preferred funding platform).
1109
+
1110
+ **If you're working in a company that's making significant use of ruby-oauth tools we'd
1111
+ appreciate it if you suggest to your company to become a ruby-oauth sponsor.**
1112
+
1113
+ You can support the development of ruby-oauth tools via
1114
+ [GitHub Sponsors][🖇sponsor],
1115
+ [Liberapay][⛳liberapay],
1116
+ [PayPal][🖇paypal],
1117
+ [Open Collective][🖇osc]
1118
+ and [Tidelift][🏙️entsup-tidelift].
1119
+
1120
+ | 📍 NOTE |
1121
+ |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
1122
+ | 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. |
1123
+
1124
+ ### Open Collective for Individuals
1125
+
1126
+ <!-- OPENCOLLECTIVE-INDIVIDUALS:START -->
1127
+ No backers yet. Be the first!
1128
+ <!-- OPENCOLLECTIVE-INDIVIDUALS:END -->
1129
+
1130
+ Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/ruby-oauth#backer)]
1131
+
1132
+ ### Open Collective for Organizations
1133
+
1134
+ <!-- OPENCOLLECTIVE-ORGANIZATIONS:START -->
1135
+ No sponsors yet. Be the first!
1136
+ <!-- OPENCOLLECTIVE-ORGANIZATIONS:END -->
1137
+
1138
+ 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)]
1139
+
1140
+ ### Another way to support open-source
1141
+
1142
+ > How wonderful it is that nobody need wait a single moment before starting to improve the world.<br/>
1143
+ >—Anne Frank
1144
+
1145
+ 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).
1146
+
1147
+ 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`.
1148
+
1149
+ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.
1150
+
1151
+ **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
1152
+
1153
+ [![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]
1154
+
697
1155
  ## 🔐 Security
698
1156
 
699
- See [SECURITY.md][🔐security].
1157
+ To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
1158
+ Tidelift will coordinate the fix and disclosure.
1159
+
1160
+ For more see [SECURITY.md][🔐security].
700
1161
 
701
1162
  ## 🤝 Contributing
702
1163
 
703
1164
  If you need some ideas of where to help, you could work on adding more code coverage,
704
- or if it is already 💯 (see [below](#code-coverage)) check [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
1165
+ or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
705
1166
  or use the gem and think about how it could be better.
706
1167
 
707
1168
  We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
@@ -715,12 +1176,13 @@ See [CONTRIBUTING.md][🤝contributing].
715
1176
  ### Code Coverage
716
1177
 
717
1178
  [![Coveralls Test Coverage][🔑coveralls-img]][🔑coveralls]
718
- [![QLTY Test Coverage][🔑qlty-covi♻️]][🔑qlty-cov]
1179
+
1180
+ [![QLTY Test Coverage][🔑qlty-covi]][🔑qlty-cov]
719
1181
 
720
1182
  ### 🪇 Code of Conduct
721
1183
 
722
- Everyone interacting in this project's codebases, issue trackers,
723
- chat rooms and mailing lists is expected to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
1184
+ Everyone interacting with this project's codebases, issue trackers,
1185
+ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
724
1186
 
725
1187
  ## 🌈 Contributors
726
1188
 
@@ -728,18 +1190,21 @@ chat rooms and mailing lists is expected to follow the [![Contributor Covenant 2
728
1190
 
729
1191
  Made with [contributors-img][🖐contrib-rocks].
730
1192
 
731
- Also see GitLab Contributors: [https://gitlab.com/oauth-xx/oauth2/-/graphs/main][🚎contributors-gl]
1193
+ Also see GitLab Contributors: [https://gitlab.com/ruby-oauth/oauth2/-/graphs/main][🚎contributors-gl]
732
1194
 
733
- ## ⭐️ Star History
1195
+ <details>
1196
+ <summary>⭐️ Star History</summary>
734
1197
 
735
- <a href="https://star-history.com/#oauth-xx/oauth2&Date">
1198
+ <a href="https://star-history.com/#ruby-oauth/oauth2&Date">
736
1199
  <picture>
737
- <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=oauth-xx/oauth2&type=Date&theme=dark" />
738
- <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=oauth-xx/oauth2&type=Date" />
739
- <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=oauth-xx/oauth2&type=Date" />
1200
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=ruby-oauth/oauth2&type=Date&theme=dark" />
1201
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=ruby-oauth/oauth2&type=Date" />
1202
+ <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=ruby-oauth/oauth2&type=Date" />
740
1203
  </picture>
741
1204
  </a>
742
1205
 
1206
+ </details>
1207
+
743
1208
  ## 📌 Versioning
744
1209
 
745
1210
  This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
@@ -748,34 +1213,35 @@ Specifically, if a minor or patch version is released that breaks backward compa
748
1213
  a new version should be immediately released that restores compatibility.
749
1214
  Breaking changes to the public API will only be introduced with new major versions.
750
1215
 
751
- ### 📌 Is "Platform Support" part of the public API?
1216
+ > dropping support for a platform is both obviously and objectively a breaking change <br/>
1217
+ >—Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
752
1218
 
753
- Yes. But I'm obligated to include notes...
1219
+ I understand that policy doesn't work universally ("exceptions to every rule!"),
1220
+ but it is the policy here.
1221
+ As such, in many cases it is good to specify a dependency on this library using
1222
+ the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
754
1223
 
755
- SemVer should, but doesn't explicitly, say that dropping support for specific Platforms
756
- is a *breaking change* to an API.
757
- It is obvious to many, but not all, and since the spec is silent, the bike shedding is endless.
1224
+ For example:
1225
+
1226
+ ```ruby
1227
+ spec.add_dependency("oauth2", "~> 2.0")
1228
+ ```
758
1229
 
759
- > dropping support for a platform is both obviously and objectively a breaking change
1230
+ <details>
1231
+ <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
760
1232
 
761
- - Jordan Harband (@ljharb, maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
1233
+ SemVer should, IMO, but doesn't explicitly, say that dropping support for specific Platforms
1234
+ is a *breaking change* to an API.
1235
+ It is obvious to many, but not all, and since the spec is silent, the bike shedding is endless.
762
1236
 
763
1237
  To get a better understanding of how SemVer is intended to work over a project's lifetime,
764
1238
  read this article from the creator of SemVer:
765
1239
 
766
1240
  - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
767
1241
 
768
- As a result of this policy, and the interpretive lens used by the maintainer,
769
- you can (and should) specify a dependency on these libraries using
770
- the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
771
-
772
- For example:
773
-
774
- ```ruby
775
- spec.add_dependency("oauth2", "~> 2.0")
776
- ```
1242
+ </details>
777
1243
 
778
- See [CHANGELOG.md][📌changelog] for list of releases.
1244
+ See [CHANGELOG.md][📌changelog] for a list of releases.
779
1245
 
780
1246
  ## 📄 License
781
1247
 
@@ -787,45 +1253,91 @@ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright
787
1253
 
788
1254
  <ul>
789
1255
  <li>
790
- 2017 - 2025 Peter H. Boling, of
1256
+ Copyright (c) 2017–2025 Peter H. Boling, of
791
1257
  <a href="https://discord.gg/3qme4XHNKN">
792
1258
  Galtzo.com
793
1259
  <picture>
794
- <img src="https://github.com/oauth-xx/oauth2/raw/main/docs/images/logo/galtzo-floss-logos-wordless.svg?raw=true" alt="Galtzo.com Logo by Aboling0, CC BY-SA 4.0" height="20">
1260
+ <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">
795
1261
  </picture>
796
- </a>, and oauth2 contributors
1262
+ </a>, and oauth2 contributors.
797
1263
  </li>
798
1264
  <li>
799
- Copyright (c) 2011 - 2013 Michael Bleigh and Intridea, Inc.
1265
+ Copyright (c) 2011-2013 Michael Bleigh and Intridea, Inc.
800
1266
  </li>
801
1267
  </ul>
802
1268
 
803
- ## 🤑 One more thing
1269
+ ## 🤑 A request for help
1270
+
1271
+ Maintainers have teeth and need to pay their dentists.
1272
+ After getting laid off in an RIF in March and filled with many dozens of rejections,
1273
+ I'm now spending ~60+ hours a week building open source tools.
1274
+ I'm hoping to be able to pay for my kids' health insurance this month,
1275
+ so if you value the work I am doing, I need your support.
1276
+ Please consider sponsoring me or the project.
1277
+
1278
+ To join the community or get help 👇️ Join the Discord.
1279
+
1280
+ [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
1281
+
1282
+ To say "thanks for maintaining such a great tool" ☝️ Join the Discord or 👇️ send money.
1283
+
1284
+ [![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]
804
1285
 
805
- You made it to the bottom of the page,
806
- so perhaps you'll indulge me for another 20 seconds.
807
- I maintain many dozens of gems, including this one,
808
- because I want Ruby to be a great place for people to solve problems, big and small.
809
- Please consider supporting my efforts via the giant yellow link below,
810
- or one of the others at the head of this README.
1286
+ ### Please give the project a star ⭐ ♥.
811
1287
 
812
- [![Buy me a latte][🖇buyme-img]][🖇buyme]
1288
+ Thanks for RTFM. ☺️
1289
+
1290
+ [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
1291
+ [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
1292
+ [⛳liberapay]: https://liberapay.com/pboling/donate
1293
+ [🖇osc-all-img]: https://img.shields.io/opencollective/all/ruby-oauth
1294
+ [🖇osc-sponsors-img]: https://img.shields.io/opencollective/sponsors/ruby-oauth
1295
+ [🖇osc-backers-img]: https://img.shields.io/opencollective/backers/ruby-oauth
1296
+ [🖇osc-backers]: https://opencollective.com/ruby-oauth#backer
1297
+ [🖇osc-backers-i]: https://opencollective.com/ruby-oauth/backers/badge.svg?style=flat
1298
+ [🖇osc-sponsors]: https://opencollective.com/ruby-oauth#sponsor
1299
+ [🖇osc-sponsors-i]: https://opencollective.com/ruby-oauth/sponsors/badge.svg?style=flat
1300
+ [🖇osc-all-bottom-img]: https://img.shields.io/opencollective/all/ruby-oauth?style=for-the-badge
1301
+ [🖇osc-sponsors-bottom-img]: https://img.shields.io/opencollective/sponsors/ruby-oauth?style=for-the-badge
1302
+ [🖇osc-backers-bottom-img]: https://img.shields.io/opencollective/backers/ruby-oauth?style=for-the-badge
1303
+ [🖇osc]: https://opencollective.com/ruby-oauth
1304
+ [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
1305
+ [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
1306
+ [🖇sponsor]: https://github.com/sponsors/pboling
1307
+ [🖇polar-img]: https://img.shields.io/badge/polar-donate-a51611.svg?style=flat
1308
+ [🖇polar]: https://polar.sh/pboling
1309
+ [🖇kofi-img]: https://img.shields.io/badge/ko--fi-✓-a51611.svg?style=flat
1310
+ [🖇kofi]: https://ko-fi.com/O5O86SNP4
1311
+ [🖇patreon-img]: https://img.shields.io/badge/patreon-donate-a51611.svg?style=flat
1312
+ [🖇patreon]: https://patreon.com/galtzo
1313
+ [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-✓-a51611.svg?style=flat
1314
+ [🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff
1315
+ [🖇buyme]: https://www.buymeacoffee.com/pboling
1316
+ [🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
1317
+ [🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
1318
+ [🖇paypal]: https://www.paypal.com/paypalme/peterboling
1319
+ [🖇floss-funding.dev]: https://floss-funding.dev
1320
+ [🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
1321
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
1322
+ [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge
813
1323
 
814
1324
  [⛳gg-discussions]: https://groups.google.com/g/oauth-ruby
815
1325
  [⛳gg-discussions-img]: https://img.shields.io/badge/google-group-0093D0.svg?style=for-the-badge&logo=google&logoColor=orange
816
1326
 
817
1327
  [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
818
- [⛳️gem-namespace]: https://github.com/oauth-xx/oauth2
819
- [⛳️namespace-img]: https://img.shields.io/badge/namespace-OAuth2-brightgreen.svg?style=flat&logo=ruby&logoColor=white
1328
+ [⛳️gem-namespace]: https://github.com/ruby-oauth/oauth2
1329
+ [⛳️namespace-img]: https://img.shields.io/badge/namespace-OAuth2-3C2D2D.svg?style=square&logo=ruby&logoColor=white
820
1330
  [⛳️gem-name]: https://rubygems.org/gems/oauth2
821
- [⛳️name-img]: https://img.shields.io/badge/name-oauth2-brightgreen.svg?style=flat&logo=rubygems&logoColor=red
822
- [🚂bdfl-blog]: http://www.railsbling.com/tags/oauth2
823
- [🚂bdfl-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
824
- [🚂bdfl-contact]: http://www.railsbling.com/contact
825
- [🚂bdfl-contact-img]: https://img.shields.io/badge/Contact-BDFL-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
1331
+ [⛳️name-img]: https://img.shields.io/badge/name-oauth2-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
1332
+ [⛳️tag-img]: https://img.shields.io/github/tag/ruby-oauth/oauth2.svg
1333
+ [⛳️tag]: http://github.com/ruby-oauth/oauth2/releases
1334
+ [🚂maint-blog]: http://www.railsbling.com/tags/oauth2
1335
+ [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
1336
+ [🚂maint-contact]: http://www.railsbling.com/contact
1337
+ [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
826
1338
  [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
827
1339
  [💖🖇linkedin-img]: https://img.shields.io/badge/PeterBoling-LinkedIn-0B66C2?style=flat&logo=newjapanprowrestling
828
- [💖✌️wellfound]: https://angel.co/u/peter-boling
1340
+ [💖✌️wellfound]: https://wellfound.com/u/peter-boling
829
1341
  [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
830
1342
  [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
831
1343
  [💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
@@ -847,78 +1359,68 @@ or one of the others at the head of this README.
847
1359
  [👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
848
1360
  [👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
849
1361
  [👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
850
- [🏙️entsup-tidelift]: https://tidelift.com/subscription
1362
+ [🏙️entsup-tidelift]: https://tidelift.com/subscription/pkg/rubygems-oauth2?utm_source=rubygems-oauth2&utm_medium=referral&utm_campaign=readme
851
1363
  [🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
852
1364
  [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
853
1365
  [💁🏼‍♂️peterboling]: http://www.peterboling.com
854
1366
  [🚂railsbling]: http://www.railsbling.com
855
1367
  [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
856
- [📜src-gl]: https://gitlab.com/oauth-xx/oauth2/
1368
+ [📜src-gl]: https://gitlab.com/ruby-oauth/oauth2/
857
1369
  [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
858
- [📜src-cb]: https://codeberg.org/oauth-xx/oauth2
1370
+ [📜src-cb]: https://codeberg.org/ruby-oauth/oauth2
859
1371
  [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green
860
- [📜src-gh]: https://github.com/oauth-xx/oauth2
1372
+ [📜src-gh]: https://github.com/ruby-oauth/oauth2
861
1373
  [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
862
1374
  [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
863
- [📜wiki]: https://gitlab.com/oauth-xx/oauth2/-/wikis/home
1375
+ [📜wiki]: https://gitlab.com/ruby-oauth/oauth2/-/wikis/home
864
1376
  [📜wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=Wiki&logoColor=white
865
1377
  [👽dl-rank]: https://rubygems.org/gems/oauth2
866
1378
  [👽dl-ranki]: https://img.shields.io/gem/rd/oauth2.svg
867
- [👽oss-help]: https://www.codetriage.com/oauth-xx/oauth2
868
- [👽oss-helpi]: https://www.codetriage.com/oauth-xx/oauth2/badges/users.svg
1379
+ [👽oss-help]: https://www.codetriage.com/ruby-oauth/oauth2
1380
+ [👽oss-helpi]: https://www.codetriage.com/ruby-oauth/oauth2/badges/users.svg
869
1381
  [👽version]: https://rubygems.org/gems/oauth2
870
1382
  [👽versioni]: https://img.shields.io/gem/v/oauth2.svg
871
- [🔑qlty-mnt]: https://qlty.sh/gh/oauth-xx/projects/oauth2
872
- [🔑qlty-mnti♻️]: https://qlty.sh/badges/d3370c2c-8791-4202-9759-76f527f76005/maintainability.svg
873
- [🔑qlty-cov]: https://qlty.sh/gh/oauth-xx/projects/oauth2
874
- [🔑qlty-covi♻️]: https://qlty.sh/badges/d3370c2c-8791-4202-9759-76f527f76005/test_coverage.svg
875
- [🔑codecov]: https://codecov.io/gh/oauth-xx/oauth2
876
- [🔑codecovi♻️]: https://codecov.io/gh/oauth-xx/oauth2/graph/badge.svg?token=bNqSzNiuo2
877
- [🔑coveralls]: https://coveralls.io/github/oauth-xx/oauth2?branch=main
878
- [🔑coveralls-img]: https://coveralls.io/repos/github/oauth-xx/oauth2/badge.svg?branch=main
879
- [🔑depfu]: https://depfu.com/github/oauth-xx/oauth2?project_id=5884
880
- [🔑depfui♻️]: https://badges.depfu.com/badges/6d34dc1ba682bbdf9ae2a97848241743/count.svg
881
- [🖐codeQL]: https://github.com/oauth-xx/oauth2/security/code-scanning
882
- [🖐codeQL-img]: https://github.com/oauth-xx/oauth2/actions/workflows/codeql-analysis.yml/badge.svg
883
- [🚎1-an-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/ancient.yml
884
- [🚎1-an-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/ancient.yml/badge.svg
885
- [🚎2-cov-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/coverage.yml
886
- [🚎2-cov-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/coverage.yml/badge.svg
887
- [🚎3-hd-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/heads.yml
888
- [🚎3-hd-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/heads.yml/badge.svg
889
- [🚎4-lg-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/legacy.yml
890
- [🚎4-lg-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/legacy.yml/badge.svg
891
- [🚎5-st-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/style.yml
892
- [🚎5-st-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/style.yml/badge.svg
893
- [🚎6-s-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/supported.yml
894
- [🚎6-s-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/supported.yml/badge.svg
895
- [🚎7-us-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/unsupported.yml
896
- [🚎7-us-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/unsupported.yml/badge.svg
897
- [🚎8-ho-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/hoary.yml
898
- [🚎8-ho-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/hoary.yml/badge.svg
899
- [🚎9-t-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/truffle.yml
900
- [🚎9-t-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/truffle.yml/badge.svg
901
- [🚎10-j-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/jruby.yml
902
- [🚎10-j-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/jruby.yml/badge.svg
903
- [🚎11-c-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/current.yml
904
- [🚎11-c-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/current.yml/badge.svg
905
- [🚎12-crh-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/current-runtime-heads.yml
906
- [🚎12-crh-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/current-runtime-heads.yml/badge.svg
907
- [🚎13-cbs-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/caboose.yml
908
- [🚎13-cbs-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/caboose.yml/badge.svg
909
- [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay
910
- [⛳liberapay]: https://liberapay.com/pboling/donate
911
- [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
912
- [🖇sponsor]: https://github.com/sponsors/pboling
913
- [🖇polar-img]: https://img.shields.io/badge/polar-donate-yellow.svg
914
- [🖇polar]: https://polar.sh/pboling
915
- [🖇kofi-img]: https://img.shields.io/badge/a_more_different_coffee-✓-yellow.svg
916
- [🖇kofi]: https://ko-fi.com/O5O86SNP4
917
- [🖇patreon-img]: https://img.shields.io/badge/patreon-donate-yellow.svg
918
- [🖇patreon]: https://patreon.com/galtzo
919
- [🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff
920
- [🖇buyme]: https://www.buymeacoffee.com/pboling
921
- [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-✓-yellow.svg?style=flat
1383
+ [🔑qlty-mnt]: https://qlty.sh/gh/ruby-oauth/projects/oauth2
1384
+ [🔑qlty-mnti]: https://qlty.sh/gh/ruby-oauth/projects/oauth2/maintainability.svg
1385
+ [🔑qlty-cov]: https://qlty.sh/gh/ruby-oauth/projects/oauth2/metrics/code?sort=coverageRating
1386
+ [🔑qlty-covi]: https://qlty.sh/gh/ruby-oauth/projects/oauth2/coverage.svg
1387
+ [🔑codecov]: https://codecov.io/gh/ruby-oauth/oauth2
1388
+ [🔑codecovi]: https://codecov.io/gh/ruby-oauth/oauth2/graph/badge.svg
1389
+ [🔑coveralls]: https://coveralls.io/github/ruby-oauth/oauth2?branch=main
1390
+ [🔑coveralls-img]: https://coveralls.io/repos/github/ruby-oauth/oauth2/badge.svg?branch=main
1391
+ [🖐codeQL]: https://github.com/ruby-oauth/oauth2/security/code-scanning
1392
+ [🖐codeQL-img]: https://github.com/ruby-oauth/oauth2/actions/workflows/codeql-analysis.yml/badge.svg
1393
+ [🚎1-an-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/ancient.yml
1394
+ [🚎1-an-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/ancient.yml/badge.svg
1395
+ [🚎2-cov-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/coverage.yml
1396
+ [🚎2-cov-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/coverage.yml/badge.svg
1397
+ [🚎3-hd-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/heads.yml
1398
+ [🚎3-hd-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/heads.yml/badge.svg
1399
+ [🚎4-lg-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/legacy.yml
1400
+ [🚎4-lg-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/legacy.yml/badge.svg
1401
+ [🚎5-st-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/style.yml
1402
+ [🚎5-st-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/style.yml/badge.svg
1403
+ [🚎6-s-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/supported.yml
1404
+ [🚎6-s-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/supported.yml/badge.svg
1405
+ [🚎7-us-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/unsupported.yml
1406
+ [🚎7-us-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/unsupported.yml/badge.svg
1407
+ [🚎8-ho-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/hoary.yml
1408
+ [🚎8-ho-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/hoary.yml/badge.svg
1409
+ [🚎9-t-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/truffle.yml
1410
+ [🚎9-t-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/truffle.yml/badge.svg
1411
+ [🚎10-j-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/jruby.yml
1412
+ [🚎10-j-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/jruby.yml/badge.svg
1413
+ [🚎11-c-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/current.yml
1414
+ [🚎11-c-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/current.yml/badge.svg
1415
+ [🚎12-crh-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/current-runtime-heads.yml
1416
+ [🚎12-crh-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/current-runtime-heads.yml/badge.svg
1417
+ [🚎13-cbs-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/caboose.yml
1418
+ [🚎13-cbs-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/caboose.yml/badge.svg
1419
+ [🚎13-🔒️-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/locked_deps.yml
1420
+ [🚎13-🔒️-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/locked_deps.yml/badge.svg
1421
+ [🚎14-🔓️-wf]: https://github.com/ruby-oauth/oauth2/actions/workflows/unlocked_deps.yml
1422
+ [🚎14-🔓️-wfi]: https://github.com/ruby-oauth/oauth2/actions/workflows/unlocked_deps.yml/badge.svg
1423
+ [💎ruby-2.2i]: https://img.shields.io/badge/Ruby-2.2_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
922
1424
  [💎ruby-2.3i]: https://img.shields.io/badge/Ruby-2.3-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
923
1425
  [💎ruby-2.4i]: https://img.shields.io/badge/Ruby-2.4-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
924
1426
  [💎ruby-2.5i]: https://img.shields.io/badge/Ruby-2.5-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
@@ -930,30 +1432,30 @@ or one of the others at the head of this README.
930
1432
  [💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
931
1433
  [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
932
1434
  [💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue
933
- [💎truby-22.3i]: https://img.shields.io/badge/Truffle_Ruby-22.3-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
934
- [💎truby-23.0i]: https://img.shields.io/badge/Truffle_Ruby-23.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
1435
+ [💎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
1436
+ [💎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
935
1437
  [💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
936
1438
  [💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green
937
1439
  [💎truby-headi]: https://img.shields.io/badge/Truffle_Ruby-HEAD-34BCB1?style=for-the-badge&logo=ruby&logoColor=blue
938
- [💎jruby-9.1i]: https://img.shields.io/badge/JRuby-9.1-FBE742?style=for-the-badge&logo=ruby&logoColor=red
939
- [💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2-FBE742?style=for-the-badge&logo=ruby&logoColor=red
940
- [💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3-FBE742?style=for-the-badge&logo=ruby&logoColor=red
1440
+ [💎jruby-9.1i]: https://img.shields.io/badge/JRuby-9.1_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
1441
+ [💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
1442
+ [💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
941
1443
  [💎jruby-9.4i]: https://img.shields.io/badge/JRuby-9.4-FBE742?style=for-the-badge&logo=ruby&logoColor=red
942
1444
  [💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green
943
1445
  [💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue
944
- [🤝gh-issues]: https://github.com/oauth-xx/oauth2/issues
945
- [🤝gh-pulls]: https://github.com/oauth-xx/oauth2/pulls
946
- [🤝gl-issues]: https://gitlab.com/oauth-xx/oauth2/-/issues
947
- [🤝gl-pulls]: https://gitlab.com/oauth-xx/oauth2/-/merge_requests
948
- [🤝cb-issues]: https://codeberg.org/oauth-xx/oauth2/issues
949
- [🤝cb-pulls]: https://codeberg.org/oauth-xx/oauth2/pulls
1446
+ [🤝gh-issues]: https://github.com/ruby-oauth/oauth2/issues
1447
+ [🤝gh-pulls]: https://github.com/ruby-oauth/oauth2/pulls
1448
+ [🤝gl-issues]: https://gitlab.com/ruby-oauth/oauth2/-/issues
1449
+ [🤝gl-pulls]: https://gitlab.com/ruby-oauth/oauth2/-/merge_requests
1450
+ [🤝cb-issues]: https://codeberg.org/ruby-oauth/oauth2/issues
1451
+ [🤝cb-pulls]: https://codeberg.org/ruby-oauth/oauth2/pulls
950
1452
  [🤝cb-donate]: https://donate.codeberg.org/
951
1453
  [🤝contributing]: CONTRIBUTING.md
952
- [🔑codecov-g♻️]: https://codecov.io/gh/oauth-xx/oauth2/graphs/tree.svg?token=bNqSzNiuo2
1454
+ [🔑codecov-g]: https://codecov.io/gh/ruby-oauth/oauth2/graphs/tree.svg
953
1455
  [🖐contrib-rocks]: https://contrib.rocks
954
- [🖐contributors]: https://github.com/oauth-xx/oauth2/graphs/contributors
955
- [🖐contributors-img]: https://contrib.rocks/image?repo=oauth-xx/oauth2
956
- [🚎contributors-gl]: https://gitlab.com/oauth-xx/oauth2/-/graphs/main
1456
+ [🖐contributors]: https://github.com/ruby-oauth/oauth2/graphs/contributors
1457
+ [🖐contributors-img]: https://contrib.rocks/image?repo=ruby-oauth/oauth2
1458
+ [🚎contributors-gl]: https://gitlab.com/ruby-oauth/oauth2/-/graphs/main
957
1459
  [🪇conduct]: CODE_OF_CONDUCT.md
958
1460
  [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
959
1461
  [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
@@ -967,7 +1469,7 @@ or one of the others at the head of this README.
967
1469
  [📌gitmoji]:https://gitmoji.dev
968
1470
  [📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square
969
1471
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
970
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.518-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1472
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.519-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
971
1473
  [🔐security]: SECURITY.md
972
1474
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
973
1475
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -978,13 +1480,13 @@ or one of the others at the head of this README.
978
1480
  [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
979
1481
  [🚎yard-current]: http://rubydoc.info/gems/oauth2
980
1482
  [🚎yard-head]: https://oauth2.galtzo.com
981
- [💎stone_checksums]: https://github.com/pboling/stone_checksums
982
- [💎SHA_checksums]: https://gitlab.com/oauth-xx/oauth2/-/tree/main/checksums
1483
+ [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
1484
+ [💎SHA_checksums]: https://gitlab.com/ruby-oauth/oauth2/-/tree/main/checksums
983
1485
  [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
984
1486
  [💎rlts-img]: https://img.shields.io/badge/code_style_%26_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
1487
+ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
1488
+ [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
985
1489
  [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
986
- [✉️discord-invite]: https://discord.gg/3qme4XHNKN
987
- [✉️discord-invite-img]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge
988
1490
 
989
1491
  <details>
990
1492
  <summary>
@@ -993,4 +1495,14 @@ or one of the others at the head of this README.
993
1495
 
994
1496
  <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%3A%2F%2Fruby.social&style=social&label=Follow%20%40galtzo%20on%20Ruby.social"></a>
995
1497
  <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%3A%2F%2Ffloss.social&style=social&label=Follow%20%40galtzo%20on%20Floss.social"></a>
1498
+
1499
+ </details>
1500
+
1501
+
1502
+ <details>
1503
+ <summary>Broken badges</summary>
1504
+
1505
+ [![Coverage Graph][🔑codecov-g]][🔑codecov]
1506
+ [![CodeCov Test Coverage][🔑codecovi]][🔑codecov]
1507
+
996
1508
  </details>