From a88753f2c7a0fb07ad9caf32cb04009f335570c7 Mon Sep 17 00:00:00 2001 From: Annibelle Boling Date: Sun, 1 Mar 2026 02:06:34 -0700 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=93=9D=20Update=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 120 +++++++----- docs/OAuth2.html | 2 +- docs/OAuth2/AccessToken.html | 2 +- docs/OAuth2/Authenticator.html | 2 +- docs/OAuth2/Client.html | 2 +- docs/OAuth2/Error.html | 2 +- docs/OAuth2/FilteredAttributes.html | 2 +- .../FilteredAttributes/ClassMethods.html | 2 +- docs/OAuth2/Response.html | 2 +- docs/OAuth2/Strategy.html | 2 +- docs/OAuth2/Strategy/Assertion.html | 2 +- docs/OAuth2/Strategy/AuthCode.html | 2 +- docs/OAuth2/Strategy/Base.html | 2 +- docs/OAuth2/Strategy/ClientCredentials.html | 2 +- docs/OAuth2/Strategy/Implicit.html | 2 +- docs/OAuth2/Strategy/Password.html | 2 +- docs/OAuth2/Version.html | 2 +- docs/_index.html | 2 +- docs/file.CHANGELOG.html | 2 +- docs/file.CITATION.html | 2 +- docs/file.CODE_OF_CONDUCT.html | 2 +- docs/file.CONTRIBUTING.html | 2 +- docs/file.FUNDING.html | 2 +- docs/file.IRP.html | 2 +- docs/file.LICENSE.html | 2 +- docs/file.OIDC.html | 2 +- docs/file.README.html | 176 +++++++++++------- docs/file.REEK.html | 2 +- docs/file.RUBOCOP.html | 2 +- docs/file.SECURITY.html | 2 +- docs/file.THREAT_MODEL.html | 2 +- docs/file.access_token.html | 2 +- docs/file.authenticator.html | 2 +- docs/file.client.html | 2 +- docs/file.error.html | 2 +- docs/file.filtered_attributes.html | 2 +- docs/file.oauth2.html | 2 +- docs/file.response.html | 2 +- docs/file.strategy.html | 2 +- docs/file.version.html | 2 +- docs/index.html | 176 +++++++++++------- docs/top-level-namespace.html | 2 +- 42 files changed, 324 insertions(+), 226 deletions(-) diff --git a/README.md b/README.md index bc17fe79..b77014dd 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,6 @@ # 🔐 OAuth 2.0 Authorization Framework -⭐️ including OAuth 2.1 draft spec & OpenID Connect (OIDC) - [![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] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Legacy][🚎4-lg-wfi]][🚎4-lg-wf] [![CI Unsupported][🚎7-us-wfi]][🚎7-us-wf] [![CI Ancient][🚎1-an-wfi]][🚎1-an-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf] `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord]. @@ -31,10 +29,10 @@ I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-ta ## 🌻 Synopsis OAuth 2.0 is the industry-standard protocol for authorization. -OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, - desktop applications, mobile phones, and living room devices. This is a RubyGem for implementing OAuth 2.0 clients (not servers) in Ruby applications. +⭐️ including OAuth 2.1 draft spec & OpenID Connect (OIDC) + ### Quick Examples
@@ -53,13 +51,14 @@ curl --request POST \ NOTE: In the ruby version below, certain params are passed to the `get_token` call, instead of the client creation. ```ruby -OAuth2::Client.new( +client = OAuth2::Client.new( "REDMOND_CLIENT_ID", # client_id "REDMOND_CLIENT_SECRET", # client_secret auth_scheme: :request_body, # Other modes are supported: :basic_auth, :tls_client_auth, :private_key_jwt token_url: "oauth2/token", # relative path, except with leading `/`, then absolute path site: "https://login.microsoftonline.com/REDMOND_REDACTED", -). # The base path for token_url when it is relative +) +client. client_credentials. # There are many other types to choose from! get_token(resource: "REDMOND_RESOURCE_UUID") ``` @@ -322,32 +321,30 @@ See [SECURITY.md][🔐security] and [IRP.md][🔐irp]. ## ⚙️ Configuration -You can turn on additional warnings. +Global settings for the library: ```ruby OAuth2.configure do |config| - # Turn on a warning like: - # OAuth2::AccessToken.from_hash: `hash` contained more than one 'token' key config.silence_extra_tokens_warning = false # default: true - # Set to true if you want to also show warnings about no tokens - config.silence_no_tokens_warning = false # default: true, + config.silence_no_tokens_warning = false # default: true end ``` -The "extra tokens" problem comes from ambiguity in the spec about which token is the right token. -Some OAuth 2.0 standards legitimately have multiple tokens. -You may need to subclass `OAuth2::AccessToken`, or write your own custom alternative to it, and pass it in. -Specify your custom class with the `access_token_class` option. +## 🔧 Basic Usage -If you only need one token, you can, as of v2.0.10, -specify the exact token name you want to extract via the `OAuth2::AccessToken` using -the `token_name` option. +### Client Initialization Options -You'll likely need to do some source diving. -This gem has 100% test coverage for lines and branches, so the specs are a great place to look for ideas. -If you have time and energy, please contribute to the documentation! +`OAuth2::Client.new` accepts several options: -## 🔧 Basic Usage +- `:site`: The base URL for the OAuth 2.0 provider. +- `:authorize_url`: The authorization endpoint (default: `"oauth/authorize"`). +- `:token_url`: The token endpoint (default: `"oauth/token"`). +- `:auth_scheme`: The authentication scheme (`:basic_auth`, `:request_body`, `:tls_client_auth`, `:private_key_jwt`). Default is `:basic_auth`. +- `:connection_opts`: Options for the underlying Faraday connection (timeouts, proxy, etc.). +- `:raise_errors`: Whether to raise `OAuth2::Error` on 400+ responses (default: `true`). + +
+ authorize_url and token_url ### `authorize_url` and `token_url` are on site root (Just Works!) @@ -394,6 +391,25 @@ client.class.name # => OAuth2::Client ``` +
+ +### Advanced Initializers + +```ruby +client = OAuth2::Client.new(id, secret, site: site) do |faraday| + faraday.request(:url_encoded) + faraday.adapter(:net_http_persistent) +end +``` + +### AccessToken Features + +Instances of `OAuth2::AccessToken` handle request signing and token expiration. + +- **Snake Case & Indifferent Access**: `response.parsed` returns a `SnakyHash` allowing access via string/symbol and snake_case keys even if the provider returns CamelCase. +- **Auto-Refresh**: You can manually check `token.expired?` and call `token.refresh`. +- **Serialization**: Persist tokens using `token.to_hash` and restore via `OAuth2::AccessToken.from_hash(client, hash)`. + ### snake_case and indifferent access in Response#parsed ```ruby @@ -546,12 +562,12 @@ client = OAuth2::Client.new( ### OAuth2::Response The `AccessToken` methods `#get`, `#post`, `#put` and `#delete` and the generic `#request` -will return an instance of the #OAuth2::Response class. +will return an instance of the `OAuth2::Response` class. This instance contains a `#parsed` method that will parse the response body and 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 -the body is a JSON object. It will return an Array if the body is a JSON -array. Otherwise, it will return the original body string. +the body is a JSON object. It will return an Array if the body is a JSON +array. Otherwise, it will return the original body string. The original response body, headers, and status can be accessed via their respective methods. @@ -593,16 +609,22 @@ Response instance will contain the `OAuth2::Error` instance. ### Authorization Grants -Note on OAuth 2.1 (draft): +Currently, the Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials, and Assertion +authentication grant types have helper strategy classes that simplify client +use. They are available via the [`#auth_code`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/auth_code.rb), +[`#implicit`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/implicit.rb), +[`#password`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/password.rb), +[`#client_credentials`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/client_credentials.rb), and +[`#assertion`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/assertion.rb) methods respectively. -- PKCE is required for all OAuth clients using the authorization code flow (especially public clients). Implement PKCE in your app when required by your provider. See RFC 7636 and RFC 8252. -- Redirect URIs must be compared using exact string matching by the Authorization Server. -- The Implicit grant (response_type=token) and the Resource Owner Password Credentials grant are omitted from OAuth 2.1; they remain here for OAuth 2.0 compatibility but should be avoided for new apps. -- Bearer tokens in the query string are omitted due to security risks; prefer Authorization header usage. -- Refresh tokens for public clients must either be sender-constrained (e.g., DPoP/MTLS) or one-time use. -- The definitions of public and confidential clients are simplified to refer only to whether the client has credentials. +#### OAuth 2.1 (draft) Note: -References: +- **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. +- **Implicit grant** (response_type=token) and **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. +- **Redirect URIs** must be compared using exact string matching by the Authorization Server. + +
+ OAuth 2.1 (draft) References - OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13 - Aaron Parecki: https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1 @@ -611,13 +633,7 @@ References: - Video: https://www.youtube.com/watch?v=g_aVPdwBTfw - Differences overview: https://fusionauth.io/learn/expert-advice/oauth/differences-between-oauth-2-oauth-2-1/ -Currently, the Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials, and Assertion -authentication grant types have helper strategy classes that simplify client -use. They are available via the [`#auth_code`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/auth_code.rb), -[`#implicit`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/implicit.rb), -[`#password`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/password.rb), -[`#client_credentials`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/client_credentials.rb), and -[`#assertion`](https://gitlab.com/ruby-oauth/oauth2/-/blob/main/lib/oauth2/strategy/assertion.rb) methods respectively. +
These aren't full examples, but demonstrative of the differences between usage for each strategy. @@ -752,7 +768,7 @@ Notes:
-### Instagram API (verb‑dependent token mode) +### Verb‑dependent Token Mode Providers like Instagram require the access token to be sent differently depending on the HTTP verb: @@ -761,6 +777,14 @@ Providers like Instagram require the access token to be sent differently dependi Since v2.0.15, you can configure an AccessToken with a verb‑dependent mode. The gem will choose how to send the token based on the request method. +Tips: + +- Avoid query‑string bearer tokens unless required by your provider. Instagram explicitly requires it for `GET` requests. +- If you need a custom rule, you can pass a `Proc` for `mode`, e.g. `mode: ->(verb) { verb == :get ? :query : :header }`. + +
+ Instagram API Example + Example: exchanging and refreshing long‑lived Instagram tokens, and making API calls ```ruby @@ -819,10 +843,7 @@ me = long_lived.get("/me", params: {fields: "id,username"}).parsed # long_lived.post("/me/media", body: {image_url: "https://...", caption: "hello"}) ``` -Tips: - -- Avoid query‑string bearer tokens unless required by your provider. Instagram explicitly requires it for `GET` requests. -- If you need a custom rule, you can pass a `Proc` for `mode`, e.g. `mode: ->(verb) { verb == :get ? :query : :header }`. +
### Refresh Tokens @@ -1063,11 +1084,12 @@ access = client.get_token({ }) ``` -### OpenID Connect (OIDC) Notes +### OpenID Connect (OIDC) -- 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. -- For private_key_jwt client authentication, provide `auth_scheme: :private_key_jwt` and ensure your key configuration matches the provider requirements. -- See [OIDC.md](OIDC.md) for a more complete OIDC overview, example, and links to the relevant specifications. +- If the token response includes an `id_token` (a JWT), this gem surfaces it in `token.params['id_token']`. +- **Note**: This gem does **not** validate the signature of the `id_token`. You must use a JWT library (like the `jwt` [gem](https://github.com/jwt/ruby-jwt)) and your provider's JWKs to verify it. +- For `private_key_jwt` client authentication, provide `auth_scheme: :private_key_jwt` and ensure your key configuration matches the provider requirements. +- See [OIDC.md](OIDC.md) for a more complete OIDC overview and examples. ### Debugging diff --git a/docs/OAuth2.html b/docs/OAuth2.html index b27a0542..02f70035 100644 --- a/docs/OAuth2.html +++ b/docs/OAuth2.html @@ -373,7 +373,7 @@

diff --git a/docs/OAuth2/AccessToken.html b/docs/OAuth2/AccessToken.html index 77789deb..5048dbe4 100644 --- a/docs/OAuth2/AccessToken.html +++ b/docs/OAuth2/AccessToken.html @@ -3077,7 +3077,7 @@

diff --git a/docs/OAuth2/Authenticator.html b/docs/OAuth2/Authenticator.html index 0b0766eb..84ab5896 100644 --- a/docs/OAuth2/Authenticator.html +++ b/docs/OAuth2/Authenticator.html @@ -883,7 +883,7 @@

diff --git a/docs/OAuth2/Client.html b/docs/OAuth2/Client.html index 80ea5708..8691bc89 100644 --- a/docs/OAuth2/Client.html +++ b/docs/OAuth2/Client.html @@ -2656,7 +2656,7 @@

diff --git a/docs/OAuth2/Error.html b/docs/OAuth2/Error.html index cc318133..d99743fd 100644 --- a/docs/OAuth2/Error.html +++ b/docs/OAuth2/Error.html @@ -772,7 +772,7 @@

diff --git a/docs/OAuth2/FilteredAttributes.html b/docs/OAuth2/FilteredAttributes.html index a69e2abd..5c044127 100644 --- a/docs/OAuth2/FilteredAttributes.html +++ b/docs/OAuth2/FilteredAttributes.html @@ -335,7 +335,7 @@

diff --git a/docs/OAuth2/FilteredAttributes/ClassMethods.html b/docs/OAuth2/FilteredAttributes/ClassMethods.html index 7081ce0b..492bb415 100644 --- a/docs/OAuth2/FilteredAttributes/ClassMethods.html +++ b/docs/OAuth2/FilteredAttributes/ClassMethods.html @@ -472,7 +472,7 @@

diff --git a/docs/OAuth2/Response.html b/docs/OAuth2/Response.html index e1d6f748..8478cfcc 100644 --- a/docs/OAuth2/Response.html +++ b/docs/OAuth2/Response.html @@ -1619,7 +1619,7 @@

diff --git a/docs/OAuth2/Strategy.html b/docs/OAuth2/Strategy.html index 2786646c..962f555e 100644 --- a/docs/OAuth2/Strategy.html +++ b/docs/OAuth2/Strategy.html @@ -107,7 +107,7 @@

Defined Under Namespace

diff --git a/docs/OAuth2/Strategy/Assertion.html b/docs/OAuth2/Strategy/Assertion.html index 4035af9e..c8242212 100644 --- a/docs/OAuth2/Strategy/Assertion.html +++ b/docs/OAuth2/Strategy/Assertion.html @@ -481,7 +481,7 @@

diff --git a/docs/OAuth2/Strategy/AuthCode.html b/docs/OAuth2/Strategy/AuthCode.html index c85d7e27..f90030b4 100644 --- a/docs/OAuth2/Strategy/AuthCode.html +++ b/docs/OAuth2/Strategy/AuthCode.html @@ -483,7 +483,7 @@

diff --git a/docs/OAuth2/Strategy/Base.html b/docs/OAuth2/Strategy/Base.html index c2a522b6..bbe124eb 100644 --- a/docs/OAuth2/Strategy/Base.html +++ b/docs/OAuth2/Strategy/Base.html @@ -195,7 +195,7 @@

diff --git a/docs/OAuth2/Strategy/ClientCredentials.html b/docs/OAuth2/Strategy/ClientCredentials.html index 9544b93c..312cef64 100644 --- a/docs/OAuth2/Strategy/ClientCredentials.html +++ b/docs/OAuth2/Strategy/ClientCredentials.html @@ -343,7 +343,7 @@

diff --git a/docs/OAuth2/Strategy/Implicit.html b/docs/OAuth2/Strategy/Implicit.html index 363abf37..52254aa0 100644 --- a/docs/OAuth2/Strategy/Implicit.html +++ b/docs/OAuth2/Strategy/Implicit.html @@ -420,7 +420,7 @@

diff --git a/docs/OAuth2/Strategy/Password.html b/docs/OAuth2/Strategy/Password.html index b47a8b63..19be718c 100644 --- a/docs/OAuth2/Strategy/Password.html +++ b/docs/OAuth2/Strategy/Password.html @@ -374,7 +374,7 @@

diff --git a/docs/OAuth2/Version.html b/docs/OAuth2/Version.html index 32285053..5b1c205f 100644 --- a/docs/OAuth2/Version.html +++ b/docs/OAuth2/Version.html @@ -111,7 +111,7 @@

diff --git a/docs/_index.html b/docs/_index.html index 59851e9b..5f892b00 100644 --- a/docs/_index.html +++ b/docs/_index.html @@ -348,7 +348,7 @@

Namespace Listing A-Z

diff --git a/docs/file.CHANGELOG.html b/docs/file.CHANGELOG.html index 0885fdec..3c7a3830 100644 --- a/docs/file.CHANGELOG.html +++ b/docs/file.CHANGELOG.html @@ -1322,7 +1322,7 @@

diff --git a/docs/file.CITATION.html b/docs/file.CITATION.html index 10aaaefb..4f74485d 100644 --- a/docs/file.CITATION.html +++ b/docs/file.CITATION.html @@ -82,7 +82,7 @@ diff --git a/docs/file.CODE_OF_CONDUCT.html b/docs/file.CODE_OF_CONDUCT.html index f8ccc4fd..3ccc9955 100644 --- a/docs/file.CODE_OF_CONDUCT.html +++ b/docs/file.CODE_OF_CONDUCT.html @@ -191,7 +191,7 @@

Attribution

diff --git a/docs/file.CONTRIBUTING.html b/docs/file.CONTRIBUTING.html index 9d3c64a9..aec9b289 100644 --- a/docs/file.CONTRIBUTING.html +++ b/docs/file.CONTRIBUTING.html @@ -304,7 +304,7 @@

Manual process

diff --git a/docs/file.FUNDING.html b/docs/file.FUNDING.html index 2685c321..4bf4bc21 100644 --- a/docs/file.FUNDING.html +++ b/docs/file.FUNDING.html @@ -99,7 +99,7 @@

Another Way to Support Open diff --git a/docs/file.IRP.html b/docs/file.IRP.html index 3527511c..2e058620 100644 --- a/docs/file.IRP.html +++ b/docs/file.IRP.html @@ -211,7 +211,7 @@

Appendix: Example checklist diff --git a/docs/file.LICENSE.html b/docs/file.LICENSE.html index f4c1f573..b13a0af7 100644 --- a/docs/file.LICENSE.html +++ b/docs/file.LICENSE.html @@ -60,7 +60,7 @@
MIT License

Copyright (c) 2017-2025 Peter H. Boling, of Galtzo.com, and oauth2 contributors
Copyright (c) 2011-2013 Michael Bleigh and Intridea, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
diff --git a/docs/file.OIDC.html b/docs/file.OIDC.html index 757bca5a..164eb4be 100644 --- a/docs/file.OIDC.html +++ b/docs/file.OIDC.html @@ -256,7 +256,7 @@

Raw OIDC with ruby-oauth/oauth2

diff --git a/docs/file.README.html b/docs/file.README.html index 71ad698b..b5574fb1 100644 --- a/docs/file.README.html +++ b/docs/file.README.html @@ -61,8 +61,6 @@

🔐 OAuth 2.0 Authorization Framework

-

⭐️ including OAuth 2.1 draft spec & OpenID Connect (OIDC)

-

Version GitHub tag (latest SemVer) License: MIT Downloads Rank Open Source Helpers CodeCov Test Coverage Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current CI JRuby Deps Locked Deps Unlocked CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL Apache SkyWalking Eyes License Compatibility Check

if ci_badges.map(&:color).detect { it != "green"} ☝️ let me know, as I may have missed the discord notification.

@@ -83,10 +81,10 @@

🔐 OAuth 2.0 Authorization Framewor

🌻 Synopsis

OAuth 2.0 is the industry-standard protocol for authorization.
-OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications,
- desktop applications, mobile phones, and living room devices.
This is a RubyGem for implementing OAuth 2.0 clients (not servers) in Ruby applications.

+

⭐️ including OAuth 2.1 draft spec & OpenID Connect (OIDC)

+

Quick Examples

@@ -103,13 +101,14 @@

Quick Examples

NOTE: In the ruby version below, certain params are passed to the get_token call, instead of the client creation.

-
OAuth2::Client.new(
+  
client = OAuth2::Client.new(
   "REDMOND_CLIENT_ID", # client_id
   "REDMOND_CLIENT_SECRET", # client_secret
   auth_scheme: :request_body, # Other modes are supported: :basic_auth, :tls_client_auth, :private_key_jwt
   token_url: "oauth2/token", # relative path, except with leading `/`, then absolute path
   site: "https://login.microsoftonline.com/REDMOND_REDACTED",
-). # The base path for token_url when it is relative
+)
+client.
   client_credentials. # There are many other types to choose from!
   get_token(resource: "REDMOND_RESOURCE_UUID")
 
@@ -580,36 +579,42 @@

Compatibility

⚙️ Configuration

-

You can turn on additional warnings.

+

Global settings for the library:

OAuth2.configure do |config|
-  # Turn on a warning like:
-  #   OAuth2::AccessToken.from_hash: `hash` contained more than one 'token' key
   config.silence_extra_tokens_warning = false # default: true
-  # Set to true if you want to also show warnings about no tokens
-  config.silence_no_tokens_warning = false # default: true,
+  config.silence_no_tokens_warning = false    # default: true
 end
 
-

The “extra tokens” problem comes from ambiguity in the spec about which token is the right token.
-Some OAuth 2.0 standards legitimately have multiple tokens.
-You may need to subclass OAuth2::AccessToken, or write your own custom alternative to it, and pass it in.
-Specify your custom class with the access_token_class option.

+

🔧 Basic Usage

-

If you only need one token, you can, as of v2.0.10,
-specify the exact token name you want to extract via the OAuth2::AccessToken using
-the token_name option.

+

Client Initialization Options

-

You’ll likely need to do some source diving.
-This gem has 100% test coverage for lines and branches, so the specs are a great place to look for ideas.
-If you have time and energy, please contribute to the documentation!

+

OAuth2::Client.new accepts several options:

-

🔧 Basic Usage

+
    +
  • +:site: The base URL for the OAuth 2.0 provider.
  • +
  • +:authorize_url: The authorization endpoint (default: "oauth/authorize").
  • +
  • +:token_url: The token endpoint (default: "oauth/token").
  • +
  • +:auth_scheme: The authentication scheme (:basic_auth, :request_body, :tls_client_auth, :private_key_jwt). Default is :basic_auth.
  • +
  • +:connection_opts: Options for the underlying Faraday connection (timeouts, proxy, etc.).
  • +
  • +:raise_errors: Whether to raise OAuth2::Error on 400+ responses (default: true).
  • +
-

+
+ authorize_url and token_url + +

authorize_url and token_url are on site root (Just Works!)

-
require "oauth2"
+  
require "oauth2"
 client = OAuth2::Client.new("client_id", "client_secret", site: "https://example.org")
 # => #<OAuth2::Client:0x00000001204c8288 @id="client_id", @secret="client_sec...
 client.auth_code.authorize_url(redirect_uri: "http://localhost:8080/oauth2/callback")
@@ -621,22 +626,22 @@ 

# => OAuth2::Response

-

Relative authorize_url and token_url (Not on site root, Just Works!)

+

Relative authorize_url and token_url (Not on site root, Just Works!)

-

In the above example, the default Authorization URL is oauth/authorize and default Access Token URL is oauth/token, and, as they are missing a leading /, both are relative.

+

In the above example, the default Authorization URL is oauth/authorize and default Access Token URL is oauth/token, and, as they are missing a leading /, both are relative.

-
client = OAuth2::Client.new("client_id", "client_secret", site: "https://example.org/nested/directory/on/your/server")
+  
client = OAuth2::Client.new("client_id", "client_secret", site: "https://example.org/nested/directory/on/your/server")
 # => #<OAuth2::Client:0x00000001204c8288 @id="client_id", @secret="client_sec...
 client.auth_code.authorize_url(redirect_uri: "http://localhost:8080/oauth2/callback")
 # => "https://example.org/nested/directory/on/your/server/oauth/authorize?client_id=client_id&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Foauth2%2Fcallback&response_type=code"
 
-

Customize authorize_url and token_url +

Customize authorize_url and token_url

-

You can specify custom URLs for authorization and access token, and when using a leading / they will not be relative, as shown below:

+

You can specify custom URLs for authorization and access token, and when using a leading / they will not be relative, as shown below:

-
client = OAuth2::Client.new(
+  
client = OAuth2::Client.new(
   "client_id",
   "client_secret",
   site: "https://example.org/nested/directory/on/your/server",
@@ -650,6 +655,29 @@ 

Customize authorize_url

+
+ +

Advanced Initializers

+ +
client = OAuth2::Client.new(id, secret, site: site) do |faraday|
+  faraday.request(:url_encoded)
+  faraday.adapter(:net_http_persistent)
+end
+
+ +

AccessToken Features

+ +

Instances of OAuth2::AccessToken handle request signing and token expiration.

+ +
    +
  • +Snake Case & Indifferent Access: response.parsed returns a SnakyHash allowing access via string/symbol and snake_case keys even if the provider returns CamelCase.
  • +
  • +Auto-Refresh: You can manually check token.expired? and call token.refresh.
  • +
  • +Serialization: Persist tokens using token.to_hash and restore via OAuth2::AccessToken.from_hash(client, hash).
  • +
+

snake_case and indifferent access in Response#parsed

response = access.get("/api/resource", params: {"query_foo" => "bar"})
@@ -795,12 +823,12 @@ 

Prefer camelCase over sna

OAuth2::Response

The AccessToken methods #get, #post, #put and #delete and the generic #request
-will return an instance of the #OAuth2::Response class.

+will return an instance of the OAuth2::Response class.

This instance contains a #parsed method that will parse the response body and
return a Hash-like SnakyHash::StringKeyed if the Content-Type is application/x-www-form-urlencoded or if
-the body is a JSON object. It will return an Array if the body is a JSON
-array. Otherwise, it will return the original body string.

+the body is a JSON object. It will return an Array if the body is a JSON
+array. Otherwise, it will return the original body string.

The original response body, headers, and status can be accessed via their
respective methods.

@@ -886,28 +914,6 @@

OAuth2::Error

Authorization Grants

-

Note on OAuth 2.1 (draft):

- -
    -
  • PKCE is required for all OAuth clients using the authorization code flow (especially public clients). Implement PKCE in your app when required by your provider. See RFC 7636 and RFC 8252.
  • -
  • Redirect URIs must be compared using exact string matching by the Authorization Server.
  • -
  • The Implicit grant (response_type=token) and the Resource Owner Password Credentials grant are omitted from OAuth 2.1; they remain here for OAuth 2.0 compatibility but should be avoided for new apps.
  • -
  • Bearer tokens in the query string are omitted due to security risks; prefer Authorization header usage.
  • -
  • Refresh tokens for public clients must either be sender-constrained (e.g., DPoP/MTLS) or one-time use.
  • -
  • The definitions of public and confidential clients are simplified to refer only to whether the client has credentials.
  • -
- -

References:

- -
    -
  • OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
  • -
  • Aaron Parecki: https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1
  • -
  • FusionAuth: https://fusionauth.io/blog/2020/04/15/whats-new-in-oauth-2-1
  • -
  • Okta: https://developer.okta.com/blog/2019/12/13/oauth-2-1-how-many-rfcs
  • -
  • Video: https://www.youtube.com/watch?v=g_aVPdwBTfw
  • -
  • Differences overview: https://fusionauth.io/learn/expert-advice/oauth/differences-between-oauth-2-oauth-2-1/
  • -
-

Currently, the Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials, and Assertion
authentication grant types have helper strategy classes that simplify client
use. They are available via the #auth_code,
@@ -916,6 +922,31 @@

Authorization Grants

#client_credentials, and
#assertion methods respectively.

+

OAuth 2.1 (draft) Note:

+ +
    +
  • +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.
  • +
  • +Implicit grant (response_type=token) and 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.
  • +
  • +Redirect URIs must be compared using exact string matching by the Authorization Server.
  • +
+ +
+ OAuth 2.1 (draft) References + +
    +
  • OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
  • +
  • Aaron Parecki: https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1
  • +
  • FusionAuth: https://fusionauth.io/blog/2020/04/15/whats-new-in-oauth-2-1
  • +
  • Okta: https://developer.okta.com/blog/2019/12/13/oauth-2-1-how-many-rfcs
  • +
  • Video: https://www.youtube.com/watch?v=g_aVPdwBTfw
  • +
  • Differences overview: https://fusionauth.io/learn/expert-advice/oauth/differences-between-oauth-2-oauth-2-1/
  • +
+ +
+

These aren’t full examples, but demonstrative of the differences between usage for each strategy.

auth_url = client.auth_code.authorize_url(redirect_uri: "http://localhost:8080/oauth/callback")
@@ -1051,7 +1082,7 @@ 

Examples

-

Instagram API (verb‑dependent token mode)

+

Verb‑dependent Token Mode

Providers like Instagram require the access token to be sent differently depending on the HTTP verb:

@@ -1062,9 +1093,19 @@

Instagram API (verb‑dependent

Since v2.0.15, you can configure an AccessToken with a verb‑dependent mode. The gem will choose how to send the token based on the request method.

-

Example: exchanging and refreshing long‑lived Instagram tokens, and making API calls

+

Tips:

-
require "oauth2"
+
    +
  • Avoid query‑string bearer tokens unless required by your provider. Instagram explicitly requires it for GET requests.
  • +
  • If you need a custom rule, you can pass a Proc for mode, e.g. mode: ->(verb) { verb == :get ? :query : :header }.
  • +
+ +
+ Instagram API Example + +

Example: exchanging and refreshing long‑lived Instagram tokens, and making API calls

+ +
require "oauth2"
 
 # NOTE: Users authenticate via Facebook Login to obtain a short‑lived user token (not shown here).
 # See Facebook Login docs for obtaining the initial short‑lived token.
@@ -1119,12 +1160,7 @@ 

Instagram API (verb‑dependent # long_lived.post("/me/media", body: {image_url: "https://...", caption: "hello"})

-

Tips:

- -
    -
  • Avoid query‑string bearer tokens unless required by your provider. Instagram explicitly requires it for GET requests.
  • -
  • If you need a custom rule, you can pass a Proc for mode, e.g. mode: ->(verb) { verb == :get ? :query : :header }.
  • -
+

Refresh Tokens

@@ -1371,12 +1407,14 @@

Making Raw Token Requests

})
-

OpenID Connect (OIDC) Notes

+

OpenID Connect (OIDC)

    -
  • 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.
  • -
  • For private_key_jwt client authentication, provide auth_scheme: :private_key_jwt and ensure your key configuration matches the provider requirements.
  • -
  • See OIDC.md for a more complete OIDC overview, example, and links to the relevant specifications.
  • +
  • If the token response includes an id_token (a JWT), this gem surfaces it in token.params['id_token'].
  • +
  • +Note: This gem does not validate the signature of the id_token. You must use a JWT library (like the jwt gem) and your provider’s JWKs to verify it.
  • +
  • For private_key_jwt client authentication, provide auth_scheme: :private_key_jwt and ensure your key configuration matches the provider requirements.
  • +
  • See OIDC.md for a more complete OIDC overview and examples.

Debugging

@@ -1607,7 +1645,7 @@

Please give the project a star ⭐ ♥ diff --git a/docs/file.REEK.html b/docs/file.REEK.html index af069f1c..a9332509 100644 --- a/docs/file.REEK.html +++ b/docs/file.REEK.html @@ -61,7 +61,7 @@ diff --git a/docs/file.RUBOCOP.html b/docs/file.RUBOCOP.html index 07742971..8abc32e6 100644 --- a/docs/file.RUBOCOP.html +++ b/docs/file.RUBOCOP.html @@ -161,7 +161,7 @@

Benefits of rubocop_gradual

diff --git a/docs/file.SECURITY.html b/docs/file.SECURITY.html index 55a279be..e341a941 100644 --- a/docs/file.SECURITY.html +++ b/docs/file.SECURITY.html @@ -93,7 +93,7 @@

Additional Support

diff --git a/docs/file.THREAT_MODEL.html b/docs/file.THREAT_MODEL.html index 12ff60e7..ca7b357b 100644 --- a/docs/file.THREAT_MODEL.html +++ b/docs/file.THREAT_MODEL.html @@ -206,7 +206,7 @@

8. References

diff --git a/docs/file.access_token.html b/docs/file.access_token.html index c4b83ebc..e45013f8 100644 --- a/docs/file.access_token.html +++ b/docs/file.access_token.html @@ -84,7 +84,7 @@ diff --git a/docs/file.authenticator.html b/docs/file.authenticator.html index 493979c7..2209675f 100644 --- a/docs/file.authenticator.html +++ b/docs/file.authenticator.html @@ -81,7 +81,7 @@ diff --git a/docs/file.client.html b/docs/file.client.html index 55199f91..f9161b88 100644 --- a/docs/file.client.html +++ b/docs/file.client.html @@ -111,7 +111,7 @@ diff --git a/docs/file.error.html b/docs/file.error.html index 9a3d11b9..bf58887a 100644 --- a/docs/file.error.html +++ b/docs/file.error.html @@ -68,7 +68,7 @@ diff --git a/docs/file.filtered_attributes.html b/docs/file.filtered_attributes.html index d601ebb5..845bedda 100644 --- a/docs/file.filtered_attributes.html +++ b/docs/file.filtered_attributes.html @@ -66,7 +66,7 @@ diff --git a/docs/file.oauth2.html b/docs/file.oauth2.html index fc822bf5..4f12cc26 100644 --- a/docs/file.oauth2.html +++ b/docs/file.oauth2.html @@ -69,7 +69,7 @@ diff --git a/docs/file.response.html b/docs/file.response.html index 2e56e14f..ef886db7 100644 --- a/docs/file.response.html +++ b/docs/file.response.html @@ -77,7 +77,7 @@ diff --git a/docs/file.strategy.html b/docs/file.strategy.html index d1809de2..c810606e 100644 --- a/docs/file.strategy.html +++ b/docs/file.strategy.html @@ -93,7 +93,7 @@ diff --git a/docs/file.version.html b/docs/file.version.html index d0a0bb19..3afe48a9 100644 --- a/docs/file.version.html +++ b/docs/file.version.html @@ -65,7 +65,7 @@ diff --git a/docs/index.html b/docs/index.html index 2de80d1d..34a9f595 100644 --- a/docs/index.html +++ b/docs/index.html @@ -61,8 +61,6 @@

🔐 OAuth 2.0 Authorization Framework

-

⭐️ including OAuth 2.1 draft spec & OpenID Connect (OIDC)

-

Version GitHub tag (latest SemVer) License: MIT Downloads Rank Open Source Helpers CodeCov Test Coverage Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current CI JRuby Deps Locked Deps Unlocked CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL Apache SkyWalking Eyes License Compatibility Check

if ci_badges.map(&:color).detect { it != "green"} ☝️ let me know, as I may have missed the discord notification.

@@ -83,10 +81,10 @@

🔐 OAuth 2.0 Authorization Framewor

🌻 Synopsis

OAuth 2.0 is the industry-standard protocol for authorization.
-OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications,
- desktop applications, mobile phones, and living room devices.
This is a RubyGem for implementing OAuth 2.0 clients (not servers) in Ruby applications.

+

⭐️ including OAuth 2.1 draft spec & OpenID Connect (OIDC)

+

Quick Examples

@@ -103,13 +101,14 @@

Quick Examples

NOTE: In the ruby version below, certain params are passed to the get_token call, instead of the client creation.

-
OAuth2::Client.new(
+  
client = OAuth2::Client.new(
   "REDMOND_CLIENT_ID", # client_id
   "REDMOND_CLIENT_SECRET", # client_secret
   auth_scheme: :request_body, # Other modes are supported: :basic_auth, :tls_client_auth, :private_key_jwt
   token_url: "oauth2/token", # relative path, except with leading `/`, then absolute path
   site: "https://login.microsoftonline.com/REDMOND_REDACTED",
-). # The base path for token_url when it is relative
+)
+client.
   client_credentials. # There are many other types to choose from!
   get_token(resource: "REDMOND_RESOURCE_UUID")
 
@@ -580,36 +579,42 @@

Compatibility

⚙️ Configuration

-

You can turn on additional warnings.

+

Global settings for the library:

OAuth2.configure do |config|
-  # Turn on a warning like:
-  #   OAuth2::AccessToken.from_hash: `hash` contained more than one 'token' key
   config.silence_extra_tokens_warning = false # default: true
-  # Set to true if you want to also show warnings about no tokens
-  config.silence_no_tokens_warning = false # default: true,
+  config.silence_no_tokens_warning = false    # default: true
 end
 
-

The “extra tokens” problem comes from ambiguity in the spec about which token is the right token.
-Some OAuth 2.0 standards legitimately have multiple tokens.
-You may need to subclass OAuth2::AccessToken, or write your own custom alternative to it, and pass it in.
-Specify your custom class with the access_token_class option.

+

🔧 Basic Usage

-

If you only need one token, you can, as of v2.0.10,
-specify the exact token name you want to extract via the OAuth2::AccessToken using
-the token_name option.

+

Client Initialization Options

-

You’ll likely need to do some source diving.
-This gem has 100% test coverage for lines and branches, so the specs are a great place to look for ideas.
-If you have time and energy, please contribute to the documentation!

+

OAuth2::Client.new accepts several options:

-

🔧 Basic Usage

+
    +
  • +:site: The base URL for the OAuth 2.0 provider.
  • +
  • +:authorize_url: The authorization endpoint (default: "oauth/authorize").
  • +
  • +:token_url: The token endpoint (default: "oauth/token").
  • +
  • +:auth_scheme: The authentication scheme (:basic_auth, :request_body, :tls_client_auth, :private_key_jwt). Default is :basic_auth.
  • +
  • +:connection_opts: Options for the underlying Faraday connection (timeouts, proxy, etc.).
  • +
  • +:raise_errors: Whether to raise OAuth2::Error on 400+ responses (default: true).
  • +
-

+
+ authorize_url and token_url + +

authorize_url and token_url are on site root (Just Works!)

-
require "oauth2"
+  
require "oauth2"
 client = OAuth2::Client.new("client_id", "client_secret", site: "https://example.org")
 # => #<OAuth2::Client:0x00000001204c8288 @id="client_id", @secret="client_sec...
 client.auth_code.authorize_url(redirect_uri: "http://localhost:8080/oauth2/callback")
@@ -621,22 +626,22 @@ 

# => OAuth2::Response

-

Relative authorize_url and token_url (Not on site root, Just Works!)

+

Relative authorize_url and token_url (Not on site root, Just Works!)

-

In the above example, the default Authorization URL is oauth/authorize and default Access Token URL is oauth/token, and, as they are missing a leading /, both are relative.

+

In the above example, the default Authorization URL is oauth/authorize and default Access Token URL is oauth/token, and, as they are missing a leading /, both are relative.

-
client = OAuth2::Client.new("client_id", "client_secret", site: "https://example.org/nested/directory/on/your/server")
+  
client = OAuth2::Client.new("client_id", "client_secret", site: "https://example.org/nested/directory/on/your/server")
 # => #<OAuth2::Client:0x00000001204c8288 @id="client_id", @secret="client_sec...
 client.auth_code.authorize_url(redirect_uri: "http://localhost:8080/oauth2/callback")
 # => "https://example.org/nested/directory/on/your/server/oauth/authorize?client_id=client_id&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Foauth2%2Fcallback&response_type=code"
 
-

Customize authorize_url and token_url +

Customize authorize_url and token_url

-

You can specify custom URLs for authorization and access token, and when using a leading / they will not be relative, as shown below:

+

You can specify custom URLs for authorization and access token, and when using a leading / they will not be relative, as shown below:

-
client = OAuth2::Client.new(
+  
client = OAuth2::Client.new(
   "client_id",
   "client_secret",
   site: "https://example.org/nested/directory/on/your/server",
@@ -650,6 +655,29 @@ 

Customize authorize_url

+
+ +

Advanced Initializers

+ +
client = OAuth2::Client.new(id, secret, site: site) do |faraday|
+  faraday.request(:url_encoded)
+  faraday.adapter(:net_http_persistent)
+end
+
+ +

AccessToken Features

+ +

Instances of OAuth2::AccessToken handle request signing and token expiration.

+ +
    +
  • +Snake Case & Indifferent Access: response.parsed returns a SnakyHash allowing access via string/symbol and snake_case keys even if the provider returns CamelCase.
  • +
  • +Auto-Refresh: You can manually check token.expired? and call token.refresh.
  • +
  • +Serialization: Persist tokens using token.to_hash and restore via OAuth2::AccessToken.from_hash(client, hash).
  • +
+

snake_case and indifferent access in Response#parsed

response = access.get("/api/resource", params: {"query_foo" => "bar"})
@@ -795,12 +823,12 @@ 

Prefer camelCase over sna

OAuth2::Response

The AccessToken methods #get, #post, #put and #delete and the generic #request
-will return an instance of the #OAuth2::Response class.

+will return an instance of the OAuth2::Response class.

This instance contains a #parsed method that will parse the response body and
return a Hash-like SnakyHash::StringKeyed if the Content-Type is application/x-www-form-urlencoded or if
-the body is a JSON object. It will return an Array if the body is a JSON
-array. Otherwise, it will return the original body string.

+the body is a JSON object. It will return an Array if the body is a JSON
+array. Otherwise, it will return the original body string.

The original response body, headers, and status can be accessed via their
respective methods.

@@ -886,28 +914,6 @@

OAuth2::Error

Authorization Grants

-

Note on OAuth 2.1 (draft):

- -
    -
  • PKCE is required for all OAuth clients using the authorization code flow (especially public clients). Implement PKCE in your app when required by your provider. See RFC 7636 and RFC 8252.
  • -
  • Redirect URIs must be compared using exact string matching by the Authorization Server.
  • -
  • The Implicit grant (response_type=token) and the Resource Owner Password Credentials grant are omitted from OAuth 2.1; they remain here for OAuth 2.0 compatibility but should be avoided for new apps.
  • -
  • Bearer tokens in the query string are omitted due to security risks; prefer Authorization header usage.
  • -
  • Refresh tokens for public clients must either be sender-constrained (e.g., DPoP/MTLS) or one-time use.
  • -
  • The definitions of public and confidential clients are simplified to refer only to whether the client has credentials.
  • -
- -

References:

- -
    -
  • OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
  • -
  • Aaron Parecki: https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1
  • -
  • FusionAuth: https://fusionauth.io/blog/2020/04/15/whats-new-in-oauth-2-1
  • -
  • Okta: https://developer.okta.com/blog/2019/12/13/oauth-2-1-how-many-rfcs
  • -
  • Video: https://www.youtube.com/watch?v=g_aVPdwBTfw
  • -
  • Differences overview: https://fusionauth.io/learn/expert-advice/oauth/differences-between-oauth-2-oauth-2-1/
  • -
-

Currently, the Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials, and Assertion
authentication grant types have helper strategy classes that simplify client
use. They are available via the #auth_code,
@@ -916,6 +922,31 @@

Authorization Grants

#client_credentials, and
#assertion methods respectively.

+

OAuth 2.1 (draft) Note:

+ +
    +
  • +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.
  • +
  • +Implicit grant (response_type=token) and 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.
  • +
  • +Redirect URIs must be compared using exact string matching by the Authorization Server.
  • +
+ +
+ OAuth 2.1 (draft) References + +
    +
  • OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13
  • +
  • Aaron Parecki: https://aaronparecki.com/2019/12/12/21/its-time-for-oauth-2-dot-1
  • +
  • FusionAuth: https://fusionauth.io/blog/2020/04/15/whats-new-in-oauth-2-1
  • +
  • Okta: https://developer.okta.com/blog/2019/12/13/oauth-2-1-how-many-rfcs
  • +
  • Video: https://www.youtube.com/watch?v=g_aVPdwBTfw
  • +
  • Differences overview: https://fusionauth.io/learn/expert-advice/oauth/differences-between-oauth-2-oauth-2-1/
  • +
+ +
+

These aren’t full examples, but demonstrative of the differences between usage for each strategy.

auth_url = client.auth_code.authorize_url(redirect_uri: "http://localhost:8080/oauth/callback")
@@ -1051,7 +1082,7 @@ 

Examples

-

Instagram API (verb‑dependent token mode)

+

Verb‑dependent Token Mode

Providers like Instagram require the access token to be sent differently depending on the HTTP verb:

@@ -1062,9 +1093,19 @@

Instagram API (verb‑dependent

Since v2.0.15, you can configure an AccessToken with a verb‑dependent mode. The gem will choose how to send the token based on the request method.

-

Example: exchanging and refreshing long‑lived Instagram tokens, and making API calls

+

Tips:

-
require "oauth2"
+
    +
  • Avoid query‑string bearer tokens unless required by your provider. Instagram explicitly requires it for GET requests.
  • +
  • If you need a custom rule, you can pass a Proc for mode, e.g. mode: ->(verb) { verb == :get ? :query : :header }.
  • +
+ +
+ Instagram API Example + +

Example: exchanging and refreshing long‑lived Instagram tokens, and making API calls

+ +
require "oauth2"
 
 # NOTE: Users authenticate via Facebook Login to obtain a short‑lived user token (not shown here).
 # See Facebook Login docs for obtaining the initial short‑lived token.
@@ -1119,12 +1160,7 @@ 

Instagram API (verb‑dependent # long_lived.post("/me/media", body: {image_url: "https://...", caption: "hello"})

-

Tips:

- -
    -
  • Avoid query‑string bearer tokens unless required by your provider. Instagram explicitly requires it for GET requests.
  • -
  • If you need a custom rule, you can pass a Proc for mode, e.g. mode: ->(verb) { verb == :get ? :query : :header }.
  • -
+

Refresh Tokens

@@ -1371,12 +1407,14 @@

Making Raw Token Requests

})
-

OpenID Connect (OIDC) Notes

+

OpenID Connect (OIDC)

    -
  • 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.
  • -
  • For private_key_jwt client authentication, provide auth_scheme: :private_key_jwt and ensure your key configuration matches the provider requirements.
  • -
  • See OIDC.md for a more complete OIDC overview, example, and links to the relevant specifications.
  • +
  • If the token response includes an id_token (a JWT), this gem surfaces it in token.params['id_token'].
  • +
  • +Note: This gem does not validate the signature of the id_token. You must use a JWT library (like the jwt gem) and your provider’s JWKs to verify it.
  • +
  • For private_key_jwt client authentication, provide auth_scheme: :private_key_jwt and ensure your key configuration matches the provider requirements.
  • +
  • See OIDC.md for a more complete OIDC overview and examples.

Debugging

@@ -1607,7 +1645,7 @@

Please give the project a star ⭐ ♥ diff --git a/docs/top-level-namespace.html b/docs/top-level-namespace.html index 3801380c..177ff205 100644 --- a/docs/top-level-namespace.html +++ b/docs/top-level-namespace.html @@ -100,7 +100,7 @@

Defined Under Namespace

From d04aa7234ad4f767ecab0143b4362c7c2bdd574f Mon Sep 17 00:00:00 2001 From: Annibelle Boling Date: Sun, 1 Mar 2026 02:08:29 -0700 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9D=20Update=20license=20year=20to?= =?UTF-8?q?=202026?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE.txt | 2 +- README.md | 2 +- docs/OAuth2.html | 2 +- docs/OAuth2/AccessToken.html | 2 +- docs/OAuth2/Authenticator.html | 2 +- docs/OAuth2/Client.html | 2 +- docs/OAuth2/Error.html | 2 +- docs/OAuth2/FilteredAttributes.html | 2 +- docs/OAuth2/FilteredAttributes/ClassMethods.html | 2 +- docs/OAuth2/Response.html | 2 +- docs/OAuth2/Strategy.html | 2 +- docs/OAuth2/Strategy/Assertion.html | 2 +- docs/OAuth2/Strategy/AuthCode.html | 2 +- docs/OAuth2/Strategy/Base.html | 2 +- docs/OAuth2/Strategy/ClientCredentials.html | 2 +- docs/OAuth2/Strategy/Implicit.html | 2 +- docs/OAuth2/Strategy/Password.html | 2 +- docs/OAuth2/Version.html | 2 +- docs/_index.html | 2 +- docs/file.CHANGELOG.html | 2 +- docs/file.CITATION.html | 2 +- docs/file.CODE_OF_CONDUCT.html | 2 +- docs/file.CONTRIBUTING.html | 2 +- docs/file.FUNDING.html | 2 +- docs/file.IRP.html | 2 +- docs/file.LICENSE.html | 4 ++-- docs/file.OIDC.html | 2 +- docs/file.README.html | 4 ++-- docs/file.REEK.html | 2 +- docs/file.RUBOCOP.html | 2 +- docs/file.SECURITY.html | 2 +- docs/file.THREAT_MODEL.html | 2 +- docs/file.access_token.html | 2 +- docs/file.authenticator.html | 2 +- docs/file.client.html | 2 +- docs/file.error.html | 2 +- docs/file.filtered_attributes.html | 2 +- docs/file.oauth2.html | 2 +- docs/file.response.html | 2 +- docs/file.strategy.html | 2 +- docs/file.version.html | 2 +- docs/index.html | 4 ++-- docs/top-level-namespace.html | 2 +- 43 files changed, 46 insertions(+), 46 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 41c8a807..7b16ce01 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017-2025 Peter H. Boling, of Galtzo.com, and oauth2 contributors +Copyright (c) 2017-2026 Peter H. Boling, of Galtzo.com, and oauth2 contributors Copyright (c) 2011-2013 Michael Bleigh and Intridea, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/README.md b/README.md index b77014dd..588a6f16 100644 --- a/README.md +++ b/README.md @@ -1261,7 +1261,7 @@ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright
  • - Copyright (c) 2017 – 2025 Peter H. Boling, of + Copyright (c) 2017 – 2026 Peter H. Boling, of Galtzo.com diff --git a/docs/OAuth2.html b/docs/OAuth2.html index 02f70035..db795699 100644 --- a/docs/OAuth2.html +++ b/docs/OAuth2.html @@ -373,7 +373,7 @@

    diff --git a/docs/OAuth2/AccessToken.html b/docs/OAuth2/AccessToken.html index 5048dbe4..686f2ca9 100644 --- a/docs/OAuth2/AccessToken.html +++ b/docs/OAuth2/AccessToken.html @@ -3077,7 +3077,7 @@

    diff --git a/docs/OAuth2/Authenticator.html b/docs/OAuth2/Authenticator.html index 84ab5896..e0baaca6 100644 --- a/docs/OAuth2/Authenticator.html +++ b/docs/OAuth2/Authenticator.html @@ -883,7 +883,7 @@

    diff --git a/docs/OAuth2/Client.html b/docs/OAuth2/Client.html index 8691bc89..32424196 100644 --- a/docs/OAuth2/Client.html +++ b/docs/OAuth2/Client.html @@ -2656,7 +2656,7 @@

    diff --git a/docs/OAuth2/Error.html b/docs/OAuth2/Error.html index d99743fd..7679bdb2 100644 --- a/docs/OAuth2/Error.html +++ b/docs/OAuth2/Error.html @@ -772,7 +772,7 @@

    diff --git a/docs/OAuth2/FilteredAttributes.html b/docs/OAuth2/FilteredAttributes.html index 5c044127..52a6cd9b 100644 --- a/docs/OAuth2/FilteredAttributes.html +++ b/docs/OAuth2/FilteredAttributes.html @@ -335,7 +335,7 @@

    diff --git a/docs/OAuth2/FilteredAttributes/ClassMethods.html b/docs/OAuth2/FilteredAttributes/ClassMethods.html index 492bb415..4d8dd37e 100644 --- a/docs/OAuth2/FilteredAttributes/ClassMethods.html +++ b/docs/OAuth2/FilteredAttributes/ClassMethods.html @@ -472,7 +472,7 @@

    diff --git a/docs/OAuth2/Response.html b/docs/OAuth2/Response.html index 8478cfcc..4d3aedc7 100644 --- a/docs/OAuth2/Response.html +++ b/docs/OAuth2/Response.html @@ -1619,7 +1619,7 @@

    diff --git a/docs/OAuth2/Strategy.html b/docs/OAuth2/Strategy.html index 962f555e..e4d80de8 100644 --- a/docs/OAuth2/Strategy.html +++ b/docs/OAuth2/Strategy.html @@ -107,7 +107,7 @@

    Defined Under Namespace

    diff --git a/docs/OAuth2/Strategy/Assertion.html b/docs/OAuth2/Strategy/Assertion.html index c8242212..83b0a56b 100644 --- a/docs/OAuth2/Strategy/Assertion.html +++ b/docs/OAuth2/Strategy/Assertion.html @@ -481,7 +481,7 @@

    diff --git a/docs/OAuth2/Strategy/AuthCode.html b/docs/OAuth2/Strategy/AuthCode.html index f90030b4..b051aa97 100644 --- a/docs/OAuth2/Strategy/AuthCode.html +++ b/docs/OAuth2/Strategy/AuthCode.html @@ -483,7 +483,7 @@

    diff --git a/docs/OAuth2/Strategy/Base.html b/docs/OAuth2/Strategy/Base.html index bbe124eb..11c634f0 100644 --- a/docs/OAuth2/Strategy/Base.html +++ b/docs/OAuth2/Strategy/Base.html @@ -195,7 +195,7 @@

    diff --git a/docs/OAuth2/Strategy/ClientCredentials.html b/docs/OAuth2/Strategy/ClientCredentials.html index 312cef64..f233fa6f 100644 --- a/docs/OAuth2/Strategy/ClientCredentials.html +++ b/docs/OAuth2/Strategy/ClientCredentials.html @@ -343,7 +343,7 @@

    diff --git a/docs/OAuth2/Strategy/Implicit.html b/docs/OAuth2/Strategy/Implicit.html index 52254aa0..3b12ec0d 100644 --- a/docs/OAuth2/Strategy/Implicit.html +++ b/docs/OAuth2/Strategy/Implicit.html @@ -420,7 +420,7 @@

    diff --git a/docs/OAuth2/Strategy/Password.html b/docs/OAuth2/Strategy/Password.html index 19be718c..819e0946 100644 --- a/docs/OAuth2/Strategy/Password.html +++ b/docs/OAuth2/Strategy/Password.html @@ -374,7 +374,7 @@

    diff --git a/docs/OAuth2/Version.html b/docs/OAuth2/Version.html index 5b1c205f..19966458 100644 --- a/docs/OAuth2/Version.html +++ b/docs/OAuth2/Version.html @@ -111,7 +111,7 @@

    diff --git a/docs/_index.html b/docs/_index.html index 5f892b00..caafcc49 100644 --- a/docs/_index.html +++ b/docs/_index.html @@ -348,7 +348,7 @@

    Namespace Listing A-Z

    diff --git a/docs/file.CHANGELOG.html b/docs/file.CHANGELOG.html index 3c7a3830..b2947ec3 100644 --- a/docs/file.CHANGELOG.html +++ b/docs/file.CHANGELOG.html @@ -1322,7 +1322,7 @@

    diff --git a/docs/file.CITATION.html b/docs/file.CITATION.html index 4f74485d..eba7442c 100644 --- a/docs/file.CITATION.html +++ b/docs/file.CITATION.html @@ -82,7 +82,7 @@ diff --git a/docs/file.CODE_OF_CONDUCT.html b/docs/file.CODE_OF_CONDUCT.html index 3ccc9955..cbeb7767 100644 --- a/docs/file.CODE_OF_CONDUCT.html +++ b/docs/file.CODE_OF_CONDUCT.html @@ -191,7 +191,7 @@

    Attribution

    diff --git a/docs/file.CONTRIBUTING.html b/docs/file.CONTRIBUTING.html index aec9b289..258f8044 100644 --- a/docs/file.CONTRIBUTING.html +++ b/docs/file.CONTRIBUTING.html @@ -304,7 +304,7 @@

    Manual process

    diff --git a/docs/file.FUNDING.html b/docs/file.FUNDING.html index 4bf4bc21..b9bcffdb 100644 --- a/docs/file.FUNDING.html +++ b/docs/file.FUNDING.html @@ -99,7 +99,7 @@

    Another Way to Support Open diff --git a/docs/file.IRP.html b/docs/file.IRP.html index 2e058620..ee5c595c 100644 --- a/docs/file.IRP.html +++ b/docs/file.IRP.html @@ -211,7 +211,7 @@

    Appendix: Example checklist diff --git a/docs/file.LICENSE.html b/docs/file.LICENSE.html index b13a0af7..590a43a5 100644 --- a/docs/file.LICENSE.html +++ b/docs/file.LICENSE.html @@ -57,10 +57,10 @@
    -
    MIT License

    Copyright (c) 2017-2025 Peter H. Boling, of Galtzo.com, and oauth2 contributors
    Copyright (c) 2011-2013 Michael Bleigh and Intridea, Inc.

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    +
    MIT License

    Copyright (c) 2017-2026 Peter H. Boling, of Galtzo.com, and oauth2 contributors
    Copyright (c) 2011-2013 Michael Bleigh and Intridea, Inc.

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    diff --git a/docs/file.OIDC.html b/docs/file.OIDC.html index 164eb4be..c61ee552 100644 --- a/docs/file.OIDC.html +++ b/docs/file.OIDC.html @@ -256,7 +256,7 @@

    Raw OIDC with ruby-oauth/oauth2

    diff --git a/docs/file.README.html b/docs/file.README.html index b5574fb1..bec62448 100644 --- a/docs/file.README.html +++ b/docs/file.README.html @@ -1599,7 +1599,7 @@
    • - Copyright (c) 2017 – 2025 Peter H. Boling, of + Copyright (c) 2017 – 2026 Peter H. Boling, of Galtzo.com @@ -1645,7 +1645,7 @@

      Please give the project a star ⭐ ♥ diff --git a/docs/file.REEK.html b/docs/file.REEK.html index a9332509..967ab7e7 100644 --- a/docs/file.REEK.html +++ b/docs/file.REEK.html @@ -61,7 +61,7 @@ diff --git a/docs/file.RUBOCOP.html b/docs/file.RUBOCOP.html index 8abc32e6..72d256e2 100644 --- a/docs/file.RUBOCOP.html +++ b/docs/file.RUBOCOP.html @@ -161,7 +161,7 @@

      Benefits of rubocop_gradual

      diff --git a/docs/file.SECURITY.html b/docs/file.SECURITY.html index e341a941..aa31edb4 100644 --- a/docs/file.SECURITY.html +++ b/docs/file.SECURITY.html @@ -93,7 +93,7 @@

      Additional Support

      diff --git a/docs/file.THREAT_MODEL.html b/docs/file.THREAT_MODEL.html index ca7b357b..dc3ccd32 100644 --- a/docs/file.THREAT_MODEL.html +++ b/docs/file.THREAT_MODEL.html @@ -206,7 +206,7 @@

      8. References

      diff --git a/docs/file.access_token.html b/docs/file.access_token.html index e45013f8..98b3421e 100644 --- a/docs/file.access_token.html +++ b/docs/file.access_token.html @@ -84,7 +84,7 @@ diff --git a/docs/file.authenticator.html b/docs/file.authenticator.html index 2209675f..ba4a93ad 100644 --- a/docs/file.authenticator.html +++ b/docs/file.authenticator.html @@ -81,7 +81,7 @@ diff --git a/docs/file.client.html b/docs/file.client.html index f9161b88..19755b28 100644 --- a/docs/file.client.html +++ b/docs/file.client.html @@ -111,7 +111,7 @@ diff --git a/docs/file.error.html b/docs/file.error.html index bf58887a..116b662b 100644 --- a/docs/file.error.html +++ b/docs/file.error.html @@ -68,7 +68,7 @@ diff --git a/docs/file.filtered_attributes.html b/docs/file.filtered_attributes.html index 845bedda..174cc722 100644 --- a/docs/file.filtered_attributes.html +++ b/docs/file.filtered_attributes.html @@ -66,7 +66,7 @@ diff --git a/docs/file.oauth2.html b/docs/file.oauth2.html index 4f12cc26..5e134511 100644 --- a/docs/file.oauth2.html +++ b/docs/file.oauth2.html @@ -69,7 +69,7 @@ diff --git a/docs/file.response.html b/docs/file.response.html index ef886db7..397e64f3 100644 --- a/docs/file.response.html +++ b/docs/file.response.html @@ -77,7 +77,7 @@ diff --git a/docs/file.strategy.html b/docs/file.strategy.html index c810606e..9da9d508 100644 --- a/docs/file.strategy.html +++ b/docs/file.strategy.html @@ -93,7 +93,7 @@ diff --git a/docs/file.version.html b/docs/file.version.html index 3afe48a9..1d2c0ebd 100644 --- a/docs/file.version.html +++ b/docs/file.version.html @@ -65,7 +65,7 @@ diff --git a/docs/index.html b/docs/index.html index 34a9f595..78d42d62 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1599,7 +1599,7 @@