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.
+
@@ -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
-Providers like Instagram require the access token to be sent differently depending on the HTTP verb:
@@ -1062,9 +1093,19 @@ 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
+