oauth2 1.4.9 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  <p align="center">
2
- <a href="http://oauth.net/2/" target="_blank" rel="noopener noreferrer">
2
+ <a href="http://oauth.net/2/" target="_blank" rel="noopener">
3
3
  <img src="https://github.com/oauth-xx/oauth2/raw/master/docs/images/logo/oauth2-logo-124px.png?raw=true" alt="OAuth 2.0 Logo by Chris Messina, CC BY-SA 3.0">
4
4
  </a>
5
- <a href="https://www.ruby-lang.org/" target="_blank" rel="noopener noreferrer">
5
+ <a href="https://www.ruby-lang.org/" target="_blank" rel="noopener">
6
6
  <img width="124px" src="https://github.com/oauth-xx/oauth2/raw/master/docs/images/logo/ruby-logo-198px.svg?raw=true" alt="Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5">
7
7
  </a>
8
8
  </p>
@@ -15,29 +15,37 @@ OAuth 2.0 focuses on client developer simplicity while providing specific author
15
15
  This is a RubyGem for implementing OAuth 2.0 clients and servers in Ruby applications.
16
16
  See the sibling `oauth` gem for OAuth 1.0 implementations in Ruby.
17
17
 
18
- ⚠️ **_WARNING_**: You are viewing the `README` of the soon-to-be-deprecated `1-4-stable`
19
- branch which for version 1.4.x releases. Version 2.0 is coming! ⚠️
20
-
21
18
  ---
22
19
 
23
20
  * [OAuth 2.0 Spec][oauth2-spec]
24
- * [OAuth 1.0 sibling gem][sibling-gem]
25
- * Help us finish release [![2.0.0 release milestone][next-milestone-pct-img]][next-milestone-pct] by submitting or reviewing PRs and issues.
26
- * Oauth2 gem is _always_ looking for additional maintainers. See [#307][maintainers-discussion].
21
+ * [oauth sibling gem][sibling-gem] for OAuth 1.0 implementations in Ruby.
27
22
 
28
23
  [oauth2-spec]: https://oauth.net/2/
29
24
  [sibling-gem]: https://github.com/oauth-xx/oauth-ruby
30
- [next-milestone-pct]: https://github.com/oauth-xx/oauth2/milestone/1
31
- [next-milestone-pct-img]: https://img.shields.io/github/milestones/progress-percent/oauth-xx/oauth2/1
32
- [maintainers-discussion]: https://github.com/oauth-xx/oauth2/issues/307
33
25
 
34
26
  ## Release Documentation
35
27
 
28
+ ### Version 2.0.x
29
+
30
+ <details>
31
+ <summary>2.0.x Readmes</summary>
32
+
33
+ | Version | Release Date | Readme |
34
+ |---------|--------------|----------------------------------------------------------|
35
+ | 2.0.3 | 2022-06-28 | https://github.com/oauth-xx/oauth2/blob/v2.0.3/README.md |
36
+ | 2.0.2 | 2022-06-24 | https://github.com/oauth-xx/oauth2/blob/v2.0.2/README.md |
37
+ | 2.0.1 | 2022-06-22 | https://github.com/oauth-xx/oauth2/blob/v2.0.1/README.md |
38
+ | 2.0.0 | 2022-06-21 | https://github.com/oauth-xx/oauth2/blob/v2.0.0/README.md |
39
+ </details>
40
+
41
+ ### Older Releases
42
+
36
43
  <details>
37
44
  <summary>1.4.x Readmes</summary>
38
45
 
39
46
  | Version | Release Date | Readme |
40
47
  |---------|--------------|----------------------------------------------------------|
48
+ | 1.4.9 | Feb 20, 2022 | https://github.com/oauth-xx/oauth2/blob/v1.4.9/README.md |
41
49
  | 1.4.8 | Feb 18, 2022 | https://github.com/oauth-xx/oauth2/blob/v1.4.8/README.md |
42
50
  | 1.4.7 | Mar 19, 2021 | https://github.com/oauth-xx/oauth2/blob/v1.4.7/README.md |
43
51
  | 1.4.6 | Mar 19, 2021 | https://github.com/oauth-xx/oauth2/blob/v1.4.6/README.md |
@@ -69,6 +77,8 @@ branch which for version 1.4.x releases. Version 2.0 is coming! ⚠️
69
77
  | < 1.0.0 | Find here | https://github.com/oauth-xx/oauth2/tags |
70
78
  </details>
71
79
 
80
+ ## Status
81
+
72
82
  <!--
73
83
  Numbering rows and badges in each row as a visual "database" lookup,
74
84
  as the table is extremely dense, and it can be very difficult to find anything
@@ -91,17 +101,20 @@ badge #s:
91
101
  🖐
92
102
  🧮
93
103
  📗
104
+
105
+ appended indicators:
106
+ ♻️ - URL needs to be updated from SASS integration. Find / Replace is insufficient.
94
107
  -->
95
108
 
96
- | | Project | oauth2 |
97
- |:----|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
98
- | 1️⃣ | name, license, docs | [![RubyGems.org][⛳️name-img]][⛳️gem] [![License: MIT][🖇src-license-img]][🖇src-license] [![FOSSA][🏘fossa-img]][🏘fossa] [![RubyDoc.info][🚎yard-img]][🚎yard] [![InchCI][🖐inch-ci-img]][🚎yard] |
99
- | 2️⃣ | version & activity | [![Gem Version][⛳️version-img]][⛳️gem] [![Total Downloads][🖇DL-total-img]][⛳️gem] [![Download Rank][🏘DL-rank-img]][⛳️gem] [![Source Code][🚎src-home-img]][🚎src-home] [![Open PRs][🖐prs-open-img]][🖐prs-open] [![Closed PRs][🧮prs-closed-img]][🧮prs-closed] |
100
- | 3️⃣ | maintanence & linting | [![Maintainability][⛳cclim-maint-img]][⛳cclim-maint] [![Helpers][🖇triage-help-img]][🖇triage-help] [![Depfu][🏘depfu-img]][🏘depfu] [![Contributors][🚎contributors-img]][🚎contributors] [![Style][🖐style-wf-img]][🖐style-wf] [![Kloc Roll][🧮kloc-img]][🧮kloc] |
101
- | 4️⃣ | testing | [![Build][⛳️tot-bld-img]][⛳️tot-bld] [![supported][🖇supported-wf-img]][🖇supported-wf] [![EOL & Code Coverage Build][🏘eol-wf-img]][🏘eol-wf] [![unsupported][🚎unsupported-wf-img]][🚎unsupported-wf] |
102
- | 5️⃣ | coverage & security | [![CodeClimate][⛳cclim-cov-img]][⛳cclim-cov] [![CodeCov][🖇codecov-img]][🖇codecov] [![Coveralls][🏘coveralls-img]][🏘coveralls] [![Security Policy][🚎sec-pol-img]][🚎sec-pol] [![CodeQL][🖐codeQL-img]][🖐codeQL] |
103
- | 6️⃣ | resources | [![Discussion][⛳gh-discussions-img]][⛳gh-discussions] [![Get help on Codementor][🖇codementor-img]][🖇codementor] [![Chat][🏘chat-img]][🏘chat] [![Blog][🚎blog-img]][🚎blog] [![Blog][🖐wiki-img]][🖐wiki] |
104
- | 7️⃣ | spread 💖 | [![Liberapay Patrons][⛳liberapay-img]][⛳liberapay] [![Sponsor Me][🖇sponsor-img]][🖇sponsor] [![Tweet @ Peter][🏘tweet-img]][🏘tweet] [🌏][aboutme] [👼][angelme] [💻][coderme] [🌹][politicme] |
109
+ | | Project | bundle add oauth2 |
110
+ |:----|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
111
+ | 1️⃣ | name, license, docs | [![RubyGems.org][⛳️name-img]][⛳️gem] [![License: MIT][🖇src-license-img]][🖇src-license] [![FOSSA][🏘fossa-img]][🏘fossa] [![RubyDoc.info][🚎yard-img]][🚎yard] [![InchCI][🖐inch-ci-img]][🚎yard] |
112
+ | 2️⃣ | version & activity | [![Gem Version][⛳️version-img]][⛳️gem] [![Total Downloads][🖇DL-total-img]][⛳️gem] [![Download Rank][🏘DL-rank-img]][⛳️gem] [![Source Code][🚎src-home-img]][🚎src-home] [![Open PRs][🖐prs-o-img]][🖐prs-o] [![Closed PRs][🧮prs-c-img]][🧮prs-c] [![Next Version][📗next-img♻️]][📗next♻️] |
113
+ | 3️⃣ | maintanence & linting | [![Maintainability][⛳cclim-maint-img♻️]][⛳cclim-maint] [![Helpers][🖇triage-help-img]][🖇triage-help] [![Depfu][🏘depfu-img♻️]][🏘depfu♻️] [![Contributors][🚎contributors-img]][🚎contributors] [![Style][🖐style-wf-img]][🖐style-wf] [![Kloc Roll][🧮kloc-img]][🧮kloc] |
114
+ | 4️⃣ | testing | [![Open Issues][⛳iss-o-img]][⛳iss-o] [![Closed Issues][🖇iss-c-img]][🖇iss-c] [![Supported][🏘sup-wf-img]][🏘sup-wf] [![Heads][🚎heads-wf-img]][🚎heads-wf] [![Unofficial Support][🖐uns-wf-img]][🖐uns-wf] [![MacOS][🧮mac-wf-img]][🧮mac-wf] [![Windows][📗win-wf-img]][📗win-wf] |
115
+ | 5️⃣ | coverage & security | [![CodeClimate][⛳cclim-cov-img♻️]][⛳cclim-cov] [![CodeCov][🖇codecov-img♻️]][🖇codecov] [![Coveralls][🏘coveralls-img]][🏘coveralls] [![Security Policy][🚎sec-pol-img]][🚎sec-pol] [![CodeQL][🖐codeQL-img]][🖐codeQL] [![Code Coverage][🧮cov-wf-img]][🧮cov-wf] |
116
+ | 6️⃣ | resources | [![Discussion][⛳gh-discussions-img]][⛳gh-discussions] [![Get help on Codementor][🖇codementor-img]][🖇codementor] [![Chat][🏘chat-img]][🏘chat] [![Blog][🚎blog-img]][🚎blog] [![Blog][🖐wiki-img]][🖐wiki] |
117
+ | 7️⃣ | spread 💖 | [![Liberapay Patrons][⛳liberapay-img]][⛳liberapay] [![Sponsor Me][🖇sponsor-img]][🖇sponsor] [![Tweet @ Peter][🏘tweet-img]][🏘tweet] [🌏][aboutme] [👼][angelme] [💻][coderme] |
105
118
 
106
119
  <!--
107
120
  The link tokens in the following sections should be kept ordered by the row and badge numbering scheme
@@ -124,18 +137,20 @@ The link tokens in the following sections should be kept ordered by the row and
124
137
  [🏘DL-rank-img]: https://img.shields.io/gem/rt/oauth2.svg
125
138
  [🚎src-home]: https://github.com/oauth-xx/oauth2
126
139
  [🚎src-home-img]: https://img.shields.io/badge/source-github-brightgreen.svg?style=flat
127
- [🖐prs-open]: https://github.com/oauth-xx/oauth2/pulls
128
- [🖐prs-open-img]: https://img.shields.io/github/issues-pr/oauth-xx/oauth2
129
- [🧮prs-closed]: https://github.com/oauth-xx/oauth2/pulls?q=is%3Apr+is%3Aclosed
130
- [🧮prs-closed-img]: https://img.shields.io/github/issues-pr-closed/oauth-xx/oauth2
140
+ [🖐prs-o]: https://github.com/oauth-xx/oauth2/pulls
141
+ [🖐prs-o-img]: https://img.shields.io/github/issues-pr/oauth-xx/oauth2
142
+ [🧮prs-c]: https://github.com/oauth-xx/oauth2/pulls?q=is%3Apr+is%3Aclosed
143
+ [🧮prs-c-img]: https://img.shields.io/github/issues-pr-closed/oauth-xx/oauth2
144
+ [📗next♻️]: https://github.com/oauth-xx/oauth2/milestone/15
145
+ [📗next-img♻️]: https://img.shields.io/github/milestones/progress/oauth-xx/oauth2/15?label=Next%20Version
131
146
 
132
147
  <!-- 3️⃣ maintanence & linting -->
133
148
  [⛳cclim-maint]: https://codeclimate.com/github/oauth-xx/oauth2/maintainability
134
- [⛳cclim-maint-img]: https://api.codeclimate.com/v1/badges/688c612528ff90a46955/maintainability
149
+ [⛳cclim-maint-img♻️]: https://api.codeclimate.com/v1/badges/688c612528ff90a46955/maintainability
135
150
  [🖇triage-help]: https://www.codetriage.com/oauth-xx/oauth2
136
151
  [🖇triage-help-img]: https://www.codetriage.com/oauth-xx/oauth2/badges/users.svg
137
- [🏘depfu]: https://depfu.com/github/oauth-xx/oauth2?project_id=4445
138
- [🏘depfu-img]: https://badges.depfu.com/badges/6d34dc1ba682bbdf9ae2a97848241743/count.svg
152
+ [🏘depfu♻️]: https://depfu.com/github/oauth-xx/oauth2?project_id=4445
153
+ [🏘depfu-img♻️]: https://badges.depfu.com/badges/6d34dc1ba682bbdf9ae2a97848241743/count.svg
139
154
  [🚎contributors]: https://github.com/oauth-xx/oauth2/graphs/contributors
140
155
  [🚎contributors-img]: https://img.shields.io/github/contributors-anon/oauth-xx/oauth2
141
156
  [🖐style-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/style.yml
@@ -144,28 +159,34 @@ The link tokens in the following sections should be kept ordered by the row and
144
159
  [🧮kloc-img]: https://img.shields.io/tokei/lines/github.com/oauth-xx/oauth2
145
160
 
146
161
  <!-- 4️⃣ testing -->
147
- [⛳️tot-bld]: https://actions-badge.atrox.dev/oauth-xx/oauth2/goto
148
- [⛳️tot-bld-img]: https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Foauth-xx%2Foauth2%2Fbadge&style=flat
149
- [🖇supported-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/supported.yml
150
- [🖇supported-wf-img]: https://github.com/oauth-xx/oauth2/actions/workflows/supported.yml/badge.svg
151
- [🏘eol-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/coverage.yml
152
- [🏘eol-wf-img]: https://github.com/oauth-xx/oauth2/actions/workflows/coverage.yml/badge.svg
153
- [🚎unsupported-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/unsupported.yml
154
- [🚎unsupported-wf-img]: https://github.com/oauth-xx/oauth2/actions/workflows/unsupported.yml/badge.svg
155
- [🖐issues]: https://github.com/oauth-xx/oauth2/issues
156
- [🖐issues-img]: https://github.com/oauth-xx/oauth2/issues
162
+ [⛳iss-o]: https://github.com/oauth-xx/oauth2/issues
163
+ [⛳iss-o-img]: https://img.shields.io/github/issues-raw/oauth-xx/oauth2
164
+ [🖇iss-c]: https://github.com/oauth-xx/oauth2/issues?q=is%3Aissue+is%3Aclosed
165
+ [🖇iss-c-img]: https://img.shields.io/github/issues-closed-raw/oauth-xx/oauth2
166
+ [🏘sup-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/supported.yml
167
+ [🏘sup-wf-img]: https://github.com/oauth-xx/oauth2/actions/workflows/supported.yml/badge.svg
168
+ [🚎heads-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/heads.yml
169
+ [🚎heads-wf-img]: https://github.com/oauth-xx/oauth2/actions/workflows/heads.yml/badge.svg
170
+ [🖐uns-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/unsupported.yml
171
+ [🖐uns-wf-img]: https://github.com/oauth-xx/oauth2/actions/workflows/unsupported.yml/badge.svg
172
+ [🧮mac-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/macos.yml
173
+ [🧮mac-wf-img]: https://github.com/oauth-xx/oauth2/actions/workflows/macos.yml/badge.svg
174
+ [📗win-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/windows.yml
175
+ [📗win-wf-img]: https://github.com/oauth-xx/oauth2/actions/workflows/windows.yml/badge.svg
157
176
 
158
177
  <!-- 5️⃣ coverage & security -->
159
178
  [⛳cclim-cov]: https://codeclimate.com/github/oauth-xx/oauth2/test_coverage
160
- [⛳cclim-cov-img]: https://api.codeclimate.com/v1/badges/688c612528ff90a46955/test_coverage
161
- [🖇codecov-img]: https://codecov.io/gh/oauth-xx/oauth2/branch/1-4-stable/graph/badge.svg?token=bNqSzNiuo2
179
+ [⛳cclim-cov-img♻️]: https://api.codeclimate.com/v1/badges/688c612528ff90a46955/test_coverage
180
+ [🖇codecov-img♻️]: https://codecov.io/gh/oauth-xx/oauth2/branch/master/graph/badge.svg?token=bNqSzNiuo2
162
181
  [🖇codecov]: https://codecov.io/gh/oauth-xx/oauth2
163
- [🏘coveralls]: https://coveralls.io/github/oauth-xx/oauth2?branch=1-4-stable
164
- [🏘coveralls-img]: https://coveralls.io/repos/github/oauth-xx/oauth2/badge.svg?branch=1-4-stable
182
+ [🏘coveralls]: https://coveralls.io/github/oauth-xx/oauth2?branch=master
183
+ [🏘coveralls-img]: https://coveralls.io/repos/github/oauth-xx/oauth2/badge.svg?branch=master
165
184
  [🚎sec-pol]: https://github.com/oauth-xx/oauth2/blob/master/SECURITY.md
166
185
  [🚎sec-pol-img]: https://img.shields.io/badge/security-policy-brightgreen.svg?style=flat
167
186
  [🖐codeQL]: https://github.com/oauth-xx/oauth2/security/code-scanning
168
187
  [🖐codeQL-img]: https://github.com/oauth-xx/oauth2/actions/workflows/codeql-analysis.yml/badge.svg
188
+ [🧮cov-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/coverage.yml
189
+ [🧮cov-wf-img]: https://github.com/oauth-xx/oauth2/actions/workflows/coverage.yml/badge.svg
169
190
 
170
191
  <!-- 6️⃣ resources -->
171
192
  [⛳gh-discussions]: https://github.com/oauth-xx/oauth2/discussions
@@ -193,31 +214,52 @@ The link tokens in the following sections should be kept ordered by the row and
193
214
  [aboutme]: https://about.me/peter.boling
194
215
  [angelme]: https://angel.co/peter-boling
195
216
  [coderme]:http://coderwall.com/pboling
196
- [politicme]: https://nationalprogressiveparty.org
197
-
198
217
 
199
218
  ## Installation
200
219
 
201
- ```shell
202
- gem install oauth2
203
- ```
220
+ Install the gem and add to the application's Gemfile by executing:
204
221
 
205
- Or inside a `Gemfile`
222
+ $ bundle add oauth2
206
223
 
207
- ```ruby
208
- gem 'oauth2'
209
- ```
210
- And then execute in a shell:
211
- ```shell
212
- bundle
213
- ```
224
+ If bundler is not being used to manage dependencies, install the gem by executing:
225
+
226
+ $ gem install oauth2
227
+
228
+ ## OAuth2 for Enterprise
229
+
230
+ Available as part of the Tidelift Subscription.
231
+
232
+ The maintainers of OAuth2 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.](https://tidelift.com/subscription/pkg/rubygems-oauth2?utm_source=rubygems-oauth2&utm_medium=referral&utm_campaign=enterprise)
214
233
 
234
+ ## Security contact information
235
+
236
+ To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
237
+ Tidelift will coordinate the fix and disclosure.
238
+
239
+ For more see [SECURITY.md][🚎sec-pol].
240
+
241
+ ## What is new for v2.0?
242
+
243
+ - Officially support Ruby versions >= 2.7
244
+ - Unofficially support Ruby versions >= 2.5
245
+ - Incidentally support Ruby versions >= 2.2
246
+ - Drop support for the expired MAC Draft (all versions)
247
+ - Support IETF rfc7523 JWT Bearer Tokens
248
+ - Support IETF rfc7231 Relative Location in Redirect
249
+ - Support IETF rfc6749 Don't set oauth params when nil
250
+ - 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)
251
+ - 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`
252
+ - Adds new option to `OAuth2::Client#get_token`:
253
+ - `:access_token_class` (`AccessToken`); user specified class to use for all calls to `get_token`
254
+ - Adds new option to `OAuth2::AccessToken#initialize`:
255
+ - `:expires_latency` (`nil`); number of seconds by which AccessToken validity will be reduced to offset latency
256
+ - [... A lot more](https://github.com/oauth-xx/oauth2/blob/master/CHANGELOG.md#2.0.0)
215
257
 
216
258
  ## Compatibility
217
259
 
218
260
  Targeted ruby compatibility is non-EOL versions of Ruby, currently 2.7, 3.0 and
219
261
  3.1. Compatibility is further distinguished by supported and unsupported versions of Ruby.
220
- Ruby is limited to 1.9+ in the gemspec for the 1.4.x series and will be 2.2+ for 2.x releases (see `master` branch).
262
+ Ruby is limited to 2.2+ for 2.x releases. See `1-4-stable` branch for older rubies.
221
263
 
222
264
  <details>
223
265
  <summary>Ruby Engine Compatibility Policy</summary>
@@ -249,28 +291,82 @@ of a major release, support for that Ruby version may be dropped.
249
291
 
250
292
  | | Ruby OAuth 2 Version | Maintenance Branch | Supported Officially | Supported Unofficially | Supported Incidentally |
251
293
  |:----|----------------------|--------------------|-------------------------|------------------------|------------------------|
252
- | 1️⃣ | 2.0.x (unreleased) | `master` | 2.7, 3.0, 3.1 | 2.6, 2.5 | 2.4, 2.3, 2.2 |
253
- | 2️⃣ | 1.4.x | `1-4-stable` | 2.5, 2.6, 2.7, 3.0, 3.1 | 2.1, 2.2, 2.3, 2.4 | 2.0, 1.9 |
294
+ | 1️⃣ | 2.0.x | `master` | 2.7, 3.0, 3.1 | 2.5, 2.6 | 2.2, 2.3, 2.4 |
295
+ | 2️⃣ | 1.4.x | `1-4-stable` | 2.5, 2.6, 2.7, 3.0, 3.1 | 2.1, 2.2, 2.3, 2.4 | 1.9, 2.0 |
254
296
  | 3️⃣ | older | N/A | Best of luck to you! | Please upgrade! | |
255
297
 
256
- NOTE: Once 2.0 is released, the 1.4 series will only receive critical bug and security updates.
298
+ NOTE: The 1.4 series will only receive critical bug and security updates.
257
299
  See [SECURITY.md][🚎sec-pol]
258
300
 
259
301
  ## Usage Examples
260
302
 
303
+ ### `authorize_url` and `token_url` are on site root (Just Works!)
304
+
261
305
  ```ruby
262
306
  require 'oauth2'
263
- client = OAuth2::Client.new('client_id', 'client_secret', :site => 'https://example.org')
264
-
265
- client.auth_code.authorize_url(:redirect_uri => 'http://localhost:8080/oauth2/callback')
266
- # => "https://example.org/oauth/authorization?response_type=code&client_id=client_id&redirect_uri=http://localhost:8080/oauth2/callback"
307
+ client = OAuth2::Client.new('client_id', 'client_secret', site: 'https://example.org')
308
+ # => #<OAuth2::Client:0x00000001204c8288 @id="client_id", @secret="client_sec...
309
+ client.auth_code.authorize_url(redirect_uri: 'http://localhost:8080/oauth2/callback')
310
+ # => "https://example.org/oauth/authorize?client_id=client_id&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Foauth2%2Fcallback&response_type=code"
267
311
 
268
- token = client.auth_code.get_token('authorization_code_value', :redirect_uri => 'http://localhost:8080/oauth2/callback', :headers => {'Authorization' => 'Basic some_password'})
269
- response = token.get('/api/resource', :params => {'query_foo' => 'bar'})
312
+ access = client.auth_code.get_token('authorization_code_value', redirect_uri: 'http://localhost:8080/oauth2/callback', headers: {'Authorization' => 'Basic some_password'})
313
+ response = access.get('/api/resource', params: {'query_foo' => 'bar'})
270
314
  response.class.name
271
315
  # => OAuth2::Response
272
316
  ```
273
317
 
318
+ ### Relative `authorize_url` and `token_url` (Not on site root, Just Works!)
319
+
320
+ In 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.
321
+
322
+ ```ruby
323
+ client = OAuth2::Client.new('client_id', 'client_secret', site: 'https://example.org/nested/directory/on/your/server')
324
+ # => #<OAuth2::Client:0x00000001204c8288 @id="client_id", @secret="client_sec...
325
+ client.auth_code.authorize_url(redirect_uri: 'http://localhost:8080/oauth2/callback')
326
+ # => "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"
327
+ ```
328
+
329
+ ### Customize `authorize_url` and `token_url`
330
+
331
+ You can specify custom URLs for authorization and access token, and when using a leading `/` they will _not be relative_, as shown below:
332
+
333
+ ```ruby
334
+ client = OAuth2::Client.new('client_id', 'client_secret',
335
+ site: 'https://example.org/nested/directory/on/your/server',
336
+ authorize_url: '/jaunty/authorize/',
337
+ token_url: '/stirrups/access_token')
338
+ # => #<OAuth2::Client:0x00000001204c8288 @id="client_id", @secret="client_sec...
339
+ client.auth_code.authorize_url(redirect_uri: 'http://localhost:8080/oauth2/callback')
340
+ # => "https://example.org/jaunty/authorize/?client_id=client_id&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Foauth2%2Fcallback&response_type=code"
341
+ client.class.name
342
+ # => OAuth2::Client
343
+ ```
344
+
345
+ ### snake_case and indifferent access in Response#parsed
346
+
347
+ ```ruby
348
+ response = access.get('/api/resource', params: {'query_foo' => 'bar'})
349
+ # Even if the actual response is CamelCase. it will be made available as snaky:
350
+ JSON.parse(response.body) # => {"accessToken"=>"aaaaaaaa", "additionalData"=>"additional"}
351
+ response.parsed # => {"access_token"=>"aaaaaaaa", "additional_data"=>"additional"}
352
+ response.parsed.access_token # => "aaaaaaaa"
353
+ response.parsed[:access_token] # => "aaaaaaaa"
354
+ response.parsed.additional_data # => "additional"
355
+ response.parsed[:additional_data] # => "additional"
356
+ response.parsed.class.name # => OAuth2::SnakyHash (subclass of Hashie::Mash::Rash, from `rash_alt` gem)
357
+ ```
358
+
359
+ #### What if I hate snakes and/or indifference?
360
+
361
+ ```ruby
362
+ response = access.get('/api/resource', params: {'query_foo' => 'bar'}, snaky: false)
363
+ JSON.parse(response.body) # => {"accessToken"=>"aaaaaaaa", "additionalData"=>"additional"}
364
+ response.parsed # => {"accessToken"=>"aaaaaaaa", "additionalData"=>"additional"}
365
+ response.parsed['accessToken'] # => "aaaaaaaa"
366
+ response.parsed['additionalData'] # => "additional"
367
+ response.parsed.class.name # => Hash (just, regular old Hash)
368
+ ```
369
+
274
370
  <details>
275
371
  <summary>Debugging</summary>
276
372
 
@@ -289,8 +385,8 @@ require 'oauth2'
289
385
  client = OAuth2::Client.new(
290
386
  'client_id',
291
387
  'client_secret',
292
- :site => 'https://example.org',
293
- :logger => Logger.new('example.log', 'weekly')
388
+ site: 'https://example.org',
389
+ logger: Logger.new('example.log', 'weekly')
294
390
  )
295
391
  ```
296
392
  </details>
@@ -301,7 +397,7 @@ The `AccessToken` methods `#get`, `#post`, `#put` and `#delete` and the generic
301
397
  will return an instance of the #OAuth2::Response class.
302
398
 
303
399
  This instance contains a `#parsed` method that will parse the response body and
304
- return a Hash if the `Content-Type` is `application/x-www-form-urlencoded` or if
400
+ return a Hash-like [`OAuth2::SnakyHash`](https://github.com/oauth-xx/oauth2/blob/master/lib/oauth2/snaky_hash.rb) if the `Content-Type` is `application/x-www-form-urlencoded` or if
305
401
  the body is a JSON object. It will return an Array if the body is a JSON
306
402
  array. Otherwise, it will return the original body string.
307
403
 
@@ -331,28 +427,42 @@ Response instance will contain the `OAuth2::Error` instance.
331
427
 
332
428
  Currently the Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials, and Assertion
333
429
  authentication grant types have helper strategy classes that simplify client
334
- use. They are available via the `#auth_code`, `#implicit`, `#password`, `#client_credentials`, and `#assertion` methods respectively.
430
+ use. They are available via the [`#auth_code`](https://github.com/oauth-xx/oauth2/blob/master/lib/oauth2/strategy/auth_code.rb), [`#implicit`](https://github.com/oauth-xx/oauth2/blob/master/lib/oauth2/strategy/implicit.rb), [`#password`](https://github.com/oauth-xx/oauth2/blob/master/lib/oauth2/strategy/password.rb), [`#client_credentials`](https://github.com/oauth-xx/oauth2/blob/master/lib/oauth2/strategy/client_credentials.rb), and [`#assertion`](https://github.com/oauth-xx/oauth2/blob/master/lib/oauth2/strategy/assertion.rb) methods respectively.
335
431
 
432
+ These aren't full examples, but demonstrative of the differences between usage for each strategy.
336
433
  ```ruby
337
- auth_url = client.auth_code.authorize_url(:redirect_uri => 'http://localhost:8080/oauth/callback')
338
- token = client.auth_code.get_token('code_value', :redirect_uri => 'http://localhost:8080/oauth/callback')
434
+ auth_url = client.auth_code.authorize_url(redirect_uri: 'http://localhost:8080/oauth/callback')
435
+ access = client.auth_code.get_token('code_value', redirect_uri: 'http://localhost:8080/oauth/callback')
339
436
 
340
- auth_url = client.implicit.authorize_url(:redirect_uri => 'http://localhost:8080/oauth/callback')
437
+ auth_url = client.implicit.authorize_url(redirect_uri: 'http://localhost:8080/oauth/callback')
341
438
  # get the token params in the callback and
342
- token = OAuth2::AccessToken.from_kvform(client, query_string)
343
-
344
- token = client.password.get_token('username', 'password')
345
-
346
- token = client.client_credentials.get_token
347
-
348
- token = client.assertion.get_token(assertion_params)
439
+ access = OAuth2::AccessToken.from_kvform(client, query_string)
440
+
441
+ access = client.password.get_token('username', 'password')
442
+
443
+ access = client.client_credentials.get_token
444
+
445
+ # Client Assertion Strategy
446
+ # see: https://tools.ietf.org/html/rfc7523
447
+ claimset = {
448
+ iss: 'http://localhost:3001',
449
+ aud: 'http://localhost:8080/oauth2/token',
450
+ sub: 'me@example.com',
451
+ exp: Time.now.utc.to_i + 3600,
452
+ }
453
+ assertion_params = [claimset, 'HS256', 'secret_key']
454
+ access = client.assertion.get_token(assertion_params)
455
+
456
+ # The `access` (i.e. access token) is then used like so:
457
+ access.token # actual access_token string, if you need it somewhere
458
+ access.get('/api/stuff') # making api calls with access token
349
459
  ```
350
460
 
351
461
  If you want to specify additional headers to be sent out with the
352
462
  request, add a 'headers' hash under 'params':
353
463
 
354
464
  ```ruby
355
- token = client.auth_code.get_token('code_value', :redirect_uri => 'http://localhost:8080/oauth/callback', :headers => {'Some' => 'Header'})
465
+ access = client.auth_code.get_token('code_value', redirect_uri: 'http://localhost:8080/oauth/callback', headers: {'Some' => 'Header'})
356
466
  ```
357
467
 
358
468
  You can always use the `#request` method on the `OAuth2::Client` instance to make
@@ -373,7 +483,7 @@ dependency on this gem using the [Pessimistic Version Constraint][pvc] with two
373
483
  For example:
374
484
 
375
485
  ```ruby
376
- spec.add_dependency 'oauth2', '~> 1.4'
486
+ spec.add_dependency 'oauth2', '~> 2.0'
377
487
  ```
378
488
 
379
489
  [semver]: http://semver.org/
@@ -395,13 +505,21 @@ spec.add_dependency 'oauth2', '~> 1.4'
395
505
 
396
506
  ## Development
397
507
 
398
- After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle excec rake spec` to run the tests.
508
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
399
509
 
400
510
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
401
511
 
402
512
  ## Contributing
403
513
 
404
- Bug reports and pull requests are welcome on GitHub at https://github.com/oauth-xx/oauth2. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
514
+ See [CONTRIBUTING.md][contributing]
515
+
516
+ [contributing]: https://github.com/oauth-xx/oauth2/blob/main/CONTRIBUTING.md
517
+
518
+ ## Contributors
519
+
520
+ [![Contributors](https://contrib.rocks/image?repo=oauth-xx/oauth2)]("https://github.com/oauth-xx/oauth2/graphs/contributors")
521
+
522
+ Made with [contributors-img](https://contrib.rocks).
405
523
 
406
524
  ## Code of Conduct
407
525
 
data/SECURITY.md ADDED
@@ -0,0 +1,20 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ |----------|---------------------------|
7
+ | 2.latest | ✅ |
8
+ | 1.latest | ✅ (security updates only) |
9
+ | older | ⛔️ |
10
+
11
+ ## Reporting a Vulnerability
12
+
13
+ To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
14
+ Tidelift will coordinate the fix and disclosure.
15
+
16
+ ## OAuth2 for Enterprise
17
+
18
+ Available as part of the Tidelift Subscription.
19
+
20
+ The maintainers of oauth2 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.](https://tidelift.com/subscription/pkg/rubygems-oauth2?utm_source=rubygems-oauth2&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
@@ -1,33 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OAuth2
4
- class AccessToken
5
- attr_reader :client, :token, :expires_in, :expires_at, :params
6
- attr_accessor :options, :refresh_token
4
+ class AccessToken # rubocop:disable Metrics/ClassLength
5
+ attr_reader :client, :token, :expires_in, :expires_at, :expires_latency, :params
6
+ attr_accessor :options, :refresh_token, :response
7
7
 
8
- # Should these methods be deprecated?
9
8
  class << self
10
9
  # Initializes an AccessToken from a Hash
11
10
  #
12
- # @param [Client] the OAuth2::Client instance
13
- # @param [Hash] a hash of AccessToken property values
14
- # @return [AccessToken] the initalized AccessToken
11
+ # @param client [Client] the OAuth2::Client instance
12
+ # @param hash [Hash] a hash of AccessToken property values
13
+ # @return [AccessToken] the initialized AccessToken
15
14
  def from_hash(client, hash)
16
15
  hash = hash.dup
17
- new(client, hash.delete('access_token') || hash.delete(:access_token), hash)
16
+ new(client, hash.delete('access_token') || hash.delete(:access_token) || hash.delete('token') || hash.delete(:token), hash)
18
17
  end
19
18
 
20
19
  # Initializes an AccessToken from a key/value application/x-www-form-urlencoded string
21
20
  #
22
21
  # @param [Client] client the OAuth2::Client instance
23
22
  # @param [String] kvform the application/x-www-form-urlencoded string
24
- # @return [AccessToken] the initalized AccessToken
23
+ # @return [AccessToken] the initialized AccessToken
25
24
  def from_kvform(client, kvform)
26
25
  from_hash(client, Rack::Utils.parse_query(kvform))
27
26
  end
27
+
28
+ def contains_token?(hash)
29
+ hash.key?('access_token') || hash.key?('id_token') || hash.key?('token')
30
+ end
28
31
  end
29
32
 
30
- # Initalize an AccessToken
33
+ # Initialize an AccessToken
31
34
  #
32
35
  # @param [Client] client the OAuth2::Client instance
33
36
  # @param [String] token the Access Token value
@@ -35,6 +38,7 @@ module OAuth2
35
38
  # @option opts [String] :refresh_token (nil) the refresh_token value
36
39
  # @option opts [FixNum, String] :expires_in (nil) the number of seconds in which the AccessToken will expire
37
40
  # @option opts [FixNum, String] :expires_at (nil) the epoch time in seconds in which AccessToken will expire
41
+ # @option opts [FixNum, String] :expires_latency (nil) the number of seconds by which AccessToken validity will be reduced to offset latency, @version 2.0+
38
42
  # @option opts [Symbol] :mode (:header) the transmission mode of the Access Token parameter value
39
43
  # one of :header, :body or :query
40
44
  # @option opts [String] :header_format ('Bearer %s') the string format to use for the Authorization header
@@ -44,16 +48,18 @@ module OAuth2
44
48
  @client = client
45
49
  @token = token.to_s
46
50
  opts = opts.dup
47
- [:refresh_token, :expires_in, :expires_at].each do |arg|
51
+ %i[refresh_token expires_in expires_at expires_latency].each do |arg|
48
52
  instance_variable_set("@#{arg}", opts.delete(arg) || opts.delete(arg.to_s))
49
53
  end
50
54
  @expires_in ||= opts.delete('expires')
51
55
  @expires_in &&= @expires_in.to_i
52
56
  @expires_at &&= convert_expires_at(@expires_at)
57
+ @expires_latency &&= @expires_latency.to_i
53
58
  @expires_at ||= Time.now.to_i + @expires_in if @expires_in
54
- @options = {:mode => opts.delete(:mode) || :header,
55
- :header_format => opts.delete(:header_format) || 'Bearer %s',
56
- :param_name => opts.delete(:param_name) || 'access_token'}
59
+ @expires_at -= @expires_latency if @expires_latency
60
+ @options = {mode: opts.delete(:mode) || :header,
61
+ header_format: opts.delete(:header_format) || 'Bearer %s',
62
+ param_name: opts.delete(:param_name) || 'access_token'}
57
63
  @params = opts
58
64
  end
59
65
 
@@ -75,29 +81,32 @@ module OAuth2
75
81
  #
76
82
  # @return [Boolean]
77
83
  def expired?
78
- expires? && (expires_at < Time.now.to_i)
84
+ expires? && (expires_at <= Time.now.to_i)
79
85
  end
80
86
 
81
87
  # Refreshes the current Access Token
82
88
  #
83
89
  # @return [AccessToken] a new AccessToken
84
90
  # @note options should be carried over to the new AccessToken
85
- def refresh!(params = {})
91
+ def refresh(params = {}, access_token_opts = {})
86
92
  raise('A refresh_token is not available') unless refresh_token
87
93
 
88
94
  params[:grant_type] = 'refresh_token'
89
95
  params[:refresh_token] = refresh_token
90
- new_token = @client.get_token(params)
96
+ new_token = @client.get_token(params, access_token_opts)
91
97
  new_token.options = options
92
98
  new_token.refresh_token = refresh_token unless new_token.refresh_token
93
99
  new_token
94
100
  end
101
+ # A compatibility alias
102
+ # @note does not modify the receiver, so bang is not the default method
103
+ alias refresh! refresh
95
104
 
96
105
  # Convert AccessToken to a hash which can be used to rebuild itself with AccessToken.from_hash
97
106
  #
98
107
  # @return [Hash] a hash of AccessToken property values
99
108
  def to_hash
100
- params.merge(:access_token => token, :refresh_token => refresh_token, :expires_at => expires_at)
109
+ params.merge(access_token: token, refresh_token: refresh_token, expires_at: expires_at)
101
110
  end
102
111
 
103
112
  # Make a request with the Access Token
@@ -105,7 +114,7 @@ module OAuth2
105
114
  # @param [Symbol] verb the HTTP request method
106
115
  # @param [String] path the HTTP URL path of the request
107
116
  # @param [Hash] opts the options to make the request with
108
- # @see Client#request
117
+ # @see Client#request
109
118
  def request(verb, path, opts = {}, &block)
110
119
  configure_authentication!(opts)
111
120
  @client.request(verb, path, opts, &block)
@@ -166,7 +175,7 @@ module OAuth2
166
175
  if opts[:body].is_a?(Hash)
167
176
  opts[:body][options[:param_name]] = token
168
177
  else
169
- opts[:body] << "&#{options[:param_name]}=#{token}"
178
+ opts[:body] += "&#{options[:param_name]}=#{token}"
170
179
  end
171
180
  # @todo support for multi-part (file uploads)
172
181
  else
@@ -37,7 +37,7 @@ module OAuth2
37
37
  end
38
38
 
39
39
  def self.encode_basic_auth(user, password)
40
- 'Basic ' + Base64.encode64(user + ':' + password).delete("\n")
40
+ "Basic #{Base64.strict_encode64("#{user}:#{password}")}"
41
41
  end
42
42
 
43
43
  private
@@ -45,13 +45,18 @@ module OAuth2
45
45
  # Adds client_id and client_secret request parameters if they are not
46
46
  # already set.
47
47
  def apply_params_auth(params)
48
- {'client_id' => id, 'client_secret' => secret}.merge(params)
48
+ result = {}
49
+ result['client_id'] = id unless id.nil?
50
+ result['client_secret'] = secret unless secret.nil?
51
+ result.merge(params)
49
52
  end
50
53
 
51
54
  # When using schemes that don't require the client_secret to be passed i.e TLS Client Auth,
52
55
  # we don't want to send the secret
53
56
  def apply_client_id(params)
54
- {'client_id' => id}.merge(params)
57
+ result = {}
58
+ result['client_id'] = id unless id.nil?
59
+ result.merge(params)
55
60
  end
56
61
 
57
62
  # Adds an `Authorization` header with Basic Auth credentials if and only if
@@ -59,7 +64,7 @@ module OAuth2
59
64
  def apply_basic_auth(params)
60
65
  headers = params.fetch(:headers, {})
61
66
  headers = basic_auth_header.merge(headers)
62
- params.merge(:headers => headers)
67
+ params.merge(headers: headers)
63
68
  end
64
69
 
65
70
  # @see https://datatracker.ietf.org/doc/html/rfc2617#section-2