access_token_wrapper 0.2.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +23 -12
- data/LICENSE.txt +1 -1
- data/README.md +26 -2
- data/access_token_wrapper.gemspec +1 -1
- data/lib/access_token_wrapper.rb +20 -0
- data/lib/access_token_wrapper/base.rb +33 -3
- data/lib/access_token_wrapper/configuration.rb +24 -0
- data/lib/access_token_wrapper/from_record.rb +60 -0
- data/lib/access_token_wrapper/version.rb +1 -1
- data/test/base_test.rb +24 -1
- data/test/from_record_test.rb +187 -0
- data/test/test_helper.rb +1 -0
- metadata +13 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 405caad8ee55bc656653df222a637247cbac4a6d7589383864dcb24d8d2934ed
|
4
|
+
data.tar.gz: 0d0462d4ac69b5d203fdef89383aa341459f8f8b0773e9498236dd39e7bfcce6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa7d945b0480387ae1c4354e3584443222e321149ec64b8e6bf533d3c0d3e9d6a45b1eef04c3efd240bbb37ed60efadf5932c330531cbcc77cc62dd989afa4f1
|
7
|
+
data.tar.gz: 11b3e0166640aef5c37e9470b15b18592c65806fd543fd8f0745fecb0966e1f65e30683e58bbdaf175f03b1fbc7c70f3a8a930a71345245d2b0cd7b2b2fcf223
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## 0.5.0 (2020-06-25)
|
2
|
+
- [FEATURE] Adds a basic configuration API with the ability to customize which exceptions are retried
|
3
|
+
- [FEATURE] Adds in `AccessTokenWrapper::FromRecord` as an alternative refresh wrapper that uses ActiveRecord locking to remove race-conditions
|
4
|
+
|
1
5
|
## 0.2.1 (2018-01-23)
|
2
6
|
- [BUGFIX] Allow the request to fallback to the old style if no expires_at provided
|
3
7
|
|
data/Gemfile.lock
CHANGED
@@ -1,34 +1,45 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
access_token_wrapper (0.2.
|
4
|
+
access_token_wrapper (0.2.1)
|
5
5
|
oauth2
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
10
|
+
addressable (2.7.0)
|
11
|
+
public_suffix (>= 2.0.2, < 5.0)
|
12
|
+
crack (0.4.3)
|
13
|
+
safe_yaml (~> 1.0.0)
|
14
|
+
faraday (1.0.1)
|
11
15
|
multipart-post (>= 1.2, < 3)
|
12
|
-
|
13
|
-
|
16
|
+
hashdiff (1.0.1)
|
17
|
+
jwt (2.2.1)
|
18
|
+
multi_json (1.14.1)
|
14
19
|
multi_xml (0.6.0)
|
15
|
-
multipart-post (2.
|
16
|
-
oauth2 (1.4.
|
17
|
-
faraday (>= 0.8, < 0
|
18
|
-
jwt (
|
20
|
+
multipart-post (2.1.1)
|
21
|
+
oauth2 (1.4.4)
|
22
|
+
faraday (>= 0.8, < 2.0)
|
23
|
+
jwt (>= 1.0, < 3.0)
|
19
24
|
multi_json (~> 1.3)
|
20
25
|
multi_xml (~> 0.5)
|
21
26
|
rack (>= 1.2, < 3)
|
22
|
-
|
23
|
-
|
27
|
+
public_suffix (4.0.5)
|
28
|
+
rack (2.2.2)
|
29
|
+
rake (13.0.1)
|
30
|
+
safe_yaml (1.0.5)
|
31
|
+
webmock (3.8.3)
|
32
|
+
addressable (>= 2.3.6)
|
33
|
+
crack (>= 0.3.2)
|
34
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
24
35
|
|
25
36
|
PLATFORMS
|
26
37
|
ruby
|
27
38
|
|
28
39
|
DEPENDENCIES
|
29
40
|
access_token_wrapper!
|
30
|
-
bundler (~> 1.3)
|
31
41
|
rake
|
42
|
+
webmock
|
32
43
|
|
33
44
|
BUNDLED WITH
|
34
|
-
1.
|
45
|
+
2.1.4
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -18,6 +18,7 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
`AccessTokenWrapper::Base`
|
21
22
|
```ruby
|
22
23
|
def access_token
|
23
24
|
@access_token ||= begin
|
@@ -43,8 +44,31 @@ def update_user_from_access_token(new_token)
|
|
43
44
|
end
|
44
45
|
```
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
or the more advanced `AccessTokenWrapper::FromRecord` that automatically locks the record on refresh to help ensure concurrency.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
def access_token
|
51
|
+
@access_token ||= begin
|
52
|
+
token = OAuth2::AccessToken.new(oauth_client, @user.access_token,
|
53
|
+
refresh_token: @user.refresh_token,
|
54
|
+
expires_at: @user.expires_at
|
55
|
+
)
|
56
|
+
AccessTokenWrapper::FromRecord.new(client: oauth_client, record: @user) do |new_token, exception|
|
57
|
+
update_user_from_access_token(new_token)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
## Configuration
|
64
|
+
```ruby
|
65
|
+
AccessTokenWrapper.configure do |config|
|
66
|
+
config.skip_statuses << 520
|
67
|
+
config.skip_refresh do |response|
|
68
|
+
response.parsed['message'].start_with?('Duplicate Idempotency')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
```
|
48
72
|
|
49
73
|
## Contributing
|
50
74
|
|
@@ -18,8 +18,8 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
22
21
|
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "webmock"
|
23
23
|
|
24
24
|
spec.add_dependency "oauth2"
|
25
25
|
end
|
data/lib/access_token_wrapper.rb
CHANGED
@@ -1 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "access_token_wrapper/base"
|
4
|
+
require "access_token_wrapper/from_record"
|
5
|
+
require "access_token_wrapper/configuration"
|
6
|
+
|
7
|
+
module AccessTokenWrapper
|
8
|
+
class << self
|
9
|
+
def configuration
|
10
|
+
@configuration ||= Configuration.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def configure
|
14
|
+
yield(configuration)
|
15
|
+
end
|
16
|
+
|
17
|
+
def reset_configuration!
|
18
|
+
@configuration = Configuration.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,26 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module AccessTokenWrapper
|
2
4
|
class Base
|
3
|
-
NON_ERROR_CODES = [402, 404, 422, 414, 429, 500, 503]
|
4
5
|
EXPIRY_GRACE_SEC = 30
|
6
|
+
|
7
|
+
def config
|
8
|
+
AccessTokenWrapper.configuration
|
9
|
+
end
|
10
|
+
|
5
11
|
attr_reader :raw_token
|
6
12
|
|
13
|
+
# This is the core functionality
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# AccessTokenWrapper::Base.new(token) do |new_token, exception|
|
17
|
+
# update_user_from_access_token(new_token)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @param [<OAuth2::AccessToken] raw_token An instance of an OAuth2::AccessToken object
|
21
|
+
# @param [&block] callback A callback that gets called when a token is refreshed,
|
22
|
+
# the callback is provided `new_token` and optional `exception` parameters
|
23
|
+
#
|
24
|
+
# @return <AccessTokenWrapper::Base>
|
25
|
+
#
|
26
|
+
# @api public
|
7
27
|
def initialize(raw_token, &callback)
|
8
28
|
@raw_token = raw_token
|
9
29
|
@callback = callback
|
10
30
|
end
|
11
31
|
|
32
|
+
private
|
33
|
+
|
12
34
|
def method_missing(method_name, *args, &block)
|
13
35
|
refresh_token! if token_expiring?
|
14
36
|
@raw_token.send(method_name, *args, &block)
|
15
37
|
rescue OAuth2::Error => exception
|
16
|
-
if
|
17
|
-
raise
|
38
|
+
if non_refreshable_exception?(exception)
|
39
|
+
raise
|
18
40
|
else
|
19
41
|
refresh_token!(exception)
|
20
42
|
@raw_token.send(method_name, *args, &block)
|
21
43
|
end
|
22
44
|
end
|
23
45
|
|
46
|
+
def non_refreshable_exception?(exception)
|
47
|
+
if config.skip_statuses.include?(exception.response.status)
|
48
|
+
true
|
49
|
+
else
|
50
|
+
config.skip_refresh_block.call(exception.response)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
24
54
|
def refresh_token!(exception = nil)
|
25
55
|
@raw_token = @raw_token.refresh!
|
26
56
|
@callback.call(@raw_token, exception)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AccessTokenWrapper
|
4
|
+
# Global configuration object
|
5
|
+
#
|
6
|
+
# AccessTokenWrapper.configure do |config|
|
7
|
+
# config.skip_statuses << 520
|
8
|
+
# config.skip_refresh do |response|
|
9
|
+
# response.parsed['message'] == 'Duplicate Idempotency Key header detected'
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
class Configuration
|
13
|
+
attr_accessor :skip_statuses, :skip_refresh_block
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@skip_statuses = [402, 404, 414, 422, 429, 500, 503]
|
17
|
+
@skip_refresh_block = ->(_response) { false }
|
18
|
+
end
|
19
|
+
|
20
|
+
def skip_refresh(&block)
|
21
|
+
@skip_refresh_block = block
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AccessTokenWrapper
|
4
|
+
class FromRecord < Base
|
5
|
+
attr_reader :record
|
6
|
+
|
7
|
+
# This is the core functionality
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# AccessTokenWrapper::FromRecord.new(client: client, record: user) do |new_token, exception|
|
11
|
+
# update_user_from_access_token(new_token)
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @param [<OAuth2::Client>] client An instance of an OAuth2::Client object
|
15
|
+
# @param [<Object>] record An AR-like object that responds to `access_token`,
|
16
|
+
# `refresh_token`, `expires_at`, `with_lock` and `reload`.
|
17
|
+
# @param [&block] callback A callback that gets called when a token is refreshed,
|
18
|
+
# the callback is provided `new_token` and optional `exception` parameters
|
19
|
+
#
|
20
|
+
# @return <AccessTokenWrapper::FromRecord>
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
def initialize(client:, record:, &callback)
|
24
|
+
@oauth_client = client
|
25
|
+
@record = record
|
26
|
+
super(build_token, &callback)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Override the refresh_token! method from the Base class to extend with locking logic
|
32
|
+
def refresh_token!(exception = nil)
|
33
|
+
@record.with_lock do
|
34
|
+
fetch_fresh_record
|
35
|
+
|
36
|
+
if token_requires_refresh?
|
37
|
+
@raw_token = @raw_token.refresh!
|
38
|
+
@callback.call(@raw_token, exception)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_token
|
44
|
+
OAuth2::AccessToken.new(@oauth_client, record.access_token, {
|
45
|
+
refresh_token: record.refresh_token,
|
46
|
+
expires_at: record.expires_at
|
47
|
+
})
|
48
|
+
end
|
49
|
+
|
50
|
+
def fetch_fresh_record
|
51
|
+
@last_token = @raw_token
|
52
|
+
@record.reload
|
53
|
+
@raw_token = build_token
|
54
|
+
end
|
55
|
+
|
56
|
+
def token_requires_refresh?
|
57
|
+
@last_token.token == @raw_token.token
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/test/base_test.rb
CHANGED
@@ -60,7 +60,6 @@ class AccessTokenWrapperTest < Minitest::Test
|
|
60
60
|
assert token.refreshed
|
61
61
|
end
|
62
62
|
|
63
|
-
|
64
63
|
def test_runs_refresh_block_if_expiring
|
65
64
|
@run = false
|
66
65
|
|
@@ -88,4 +87,28 @@ class AccessTokenWrapperTest < Minitest::Test
|
|
88
87
|
assert !@run
|
89
88
|
assert !token.refreshed
|
90
89
|
end
|
90
|
+
|
91
|
+
def test_doesnt_run_refresh_block_with_skip_block
|
92
|
+
AccessTokenWrapper.configure do |config|
|
93
|
+
config.skip_refresh do |response|
|
94
|
+
true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
@run = false
|
99
|
+
|
100
|
+
token = described_class.new(FakeToken.new) do |new_token, exception|
|
101
|
+
@run = true
|
102
|
+
end
|
103
|
+
|
104
|
+
begin
|
105
|
+
token.get_and_raise(401)
|
106
|
+
rescue OAuth2::Error
|
107
|
+
end
|
108
|
+
|
109
|
+
assert !@run
|
110
|
+
assert !token.refreshed
|
111
|
+
ensure
|
112
|
+
AccessTokenWrapper.reset_configuration!
|
113
|
+
end
|
91
114
|
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FromRecordTest < Minitest::Test
|
4
|
+
def described_class
|
5
|
+
AccessTokenWrapper::FromRecord
|
6
|
+
end
|
7
|
+
|
8
|
+
class FakeRecord
|
9
|
+
class << self
|
10
|
+
attr_accessor :locked
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :id, :reloaded
|
14
|
+
attr_accessor :access_token, :refresh_token, :expires_at
|
15
|
+
attr_writer :fresh_token
|
16
|
+
|
17
|
+
def initialize(access_token: 'ABC', refresh_token: 'DEF', expires_at: Time.now.to_i + 3600)
|
18
|
+
update_from_access_token(OpenStruct.new(token: access_token, refresh_token: refresh_token, expires_at: expires_at))
|
19
|
+
@id = 42
|
20
|
+
@fresh_token = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_from_access_token(token)
|
24
|
+
@access_token = token.token
|
25
|
+
@refresh_token = token.refresh_token
|
26
|
+
@expires_at = token.expires_at
|
27
|
+
end
|
28
|
+
|
29
|
+
def reload
|
30
|
+
@reloaded = true
|
31
|
+
if @fresh_token
|
32
|
+
update_from_access_token(@fresh_token)
|
33
|
+
@fresh_token = nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def with_lock
|
38
|
+
true while self.class.locked
|
39
|
+
|
40
|
+
self.class.locked = true
|
41
|
+
sleep 0.1
|
42
|
+
yield
|
43
|
+
self.class.locked = false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class ExpiringFakeRecord < FakeRecord
|
48
|
+
def reload
|
49
|
+
@access_token = access_token + "*"
|
50
|
+
@refresh_token = refresh_token + "*"
|
51
|
+
@expires_at = Time.now.to_i + 3600
|
52
|
+
super
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def client
|
57
|
+
@client ||= OAuth2::Client.new('AAA', 'BBB', site: 'http://localhost:3000')
|
58
|
+
end
|
59
|
+
|
60
|
+
def setup
|
61
|
+
stub_request(:get, "http://localhost:3000/200").to_return(status: 200, body: "")
|
62
|
+
stub_request(:get, "http://localhost:3000/401").to_return({ status: 401, body: "" }, { status: 200, body: "" })
|
63
|
+
stub_request(:get, "http://localhost:3000/429").to_return(status: 429, body: "")
|
64
|
+
end
|
65
|
+
|
66
|
+
def stub_token_refresh
|
67
|
+
stub_request(:post, "http://localhost:3000/oauth/token").with(body: {"client_id"=>"AAA", "client_secret"=>"BBB", "grant_type"=>"refresh_token", "refresh_token"=>"DEF"}).to_return(status: 200, headers: { 'Content-Type' => 'application/json' }, body: token_response.to_json).times(1)
|
68
|
+
end
|
69
|
+
|
70
|
+
def stub_token_refresh_with_wait
|
71
|
+
stub_request(:post, "http://localhost:3000/oauth/token").to_return(status: 200, headers: { 'Content-Type' => 'application/json' }, body: lambda { |request| sleep 0.1; token_response.to_json }).times(1)
|
72
|
+
end
|
73
|
+
|
74
|
+
def token_response
|
75
|
+
{
|
76
|
+
"access_token": "57ed301af04bf35b40f255feb5ef469ab2f046aff14",
|
77
|
+
"expires_in": 7200,
|
78
|
+
"refresh_token": "026b343de07818b3ffebfb3001eff9a00aea43da0 ",
|
79
|
+
"scope": "public",
|
80
|
+
"token_type": "bearer"
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_doesnt_run_block_if_no_exception
|
85
|
+
@run = false
|
86
|
+
|
87
|
+
token = described_class.new(client: client, record: FakeRecord.new) do |new_token, exception|
|
88
|
+
@run = true
|
89
|
+
end
|
90
|
+
|
91
|
+
token.get('/200')
|
92
|
+
assert !@run
|
93
|
+
assert !token.record.reloaded
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_runs_refresh_block_if_exception
|
97
|
+
@run = false
|
98
|
+
stub_refresh = stub_token_refresh
|
99
|
+
|
100
|
+
token = described_class.new(client: client, record: FakeRecord.new) do |new_token, exception|
|
101
|
+
@run = true
|
102
|
+
end
|
103
|
+
|
104
|
+
token.get('/401')
|
105
|
+
assert @run
|
106
|
+
assert token.record.reloaded
|
107
|
+
assert_requested(stub_refresh)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_runs_refresh_block_if_expiring
|
111
|
+
@run = false
|
112
|
+
stub_refresh = stub_token_refresh
|
113
|
+
token = described_class.new(client: client, record: FakeRecord.new(expires_at: Time.now.to_i - 1)) do |new_token, exception|
|
114
|
+
@run = true
|
115
|
+
end
|
116
|
+
|
117
|
+
token.get('/200')
|
118
|
+
assert @run
|
119
|
+
assert token.record.reloaded
|
120
|
+
assert_requested(stub_refresh)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_doesnt_run_block_if_non_auth_exception
|
124
|
+
@run = false
|
125
|
+
|
126
|
+
token = described_class.new(client: client, record: FakeRecord.new) do |new_token, exception|
|
127
|
+
@run = true
|
128
|
+
end
|
129
|
+
|
130
|
+
begin
|
131
|
+
token.get('/429')
|
132
|
+
rescue OAuth2::Error
|
133
|
+
end
|
134
|
+
|
135
|
+
assert !@run
|
136
|
+
assert !token.record.reloaded
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_refreshes_record_and_halts_api_request_if_not_needed
|
140
|
+
@run = false
|
141
|
+
stub_refresh = stub_token_refresh
|
142
|
+
|
143
|
+
token = described_class.new(client: client, record: ExpiringFakeRecord.new) do |new_token, exception|
|
144
|
+
@run = true
|
145
|
+
end
|
146
|
+
|
147
|
+
token.get('/401')
|
148
|
+
|
149
|
+
assert !@run
|
150
|
+
assert_not_requested(stub_refresh)
|
151
|
+
assert token.record.reloaded
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_that_the_lock_locks_multiple_requests
|
155
|
+
@results = []
|
156
|
+
record = FakeRecord.new(expires_at: Time.now.to_i-1)
|
157
|
+
record_copy = FakeRecord.new(expires_at: Time.now.to_i-1)
|
158
|
+
|
159
|
+
token = described_class.new(client: client, record: record) do |new_token, exception|
|
160
|
+
record.update_from_access_token(new_token)
|
161
|
+
record_copy.fresh_token = new_token
|
162
|
+
@run = true
|
163
|
+
end
|
164
|
+
|
165
|
+
token2 = described_class.new(client: client, record: record_copy) do |new_token, exception|
|
166
|
+
@run = true
|
167
|
+
end
|
168
|
+
|
169
|
+
stub_refresh = stub_token_refresh_with_wait
|
170
|
+
|
171
|
+
new_thread = Thread.new do
|
172
|
+
@results << :before_primary
|
173
|
+
token.get('/200')
|
174
|
+
@results << :after_primary
|
175
|
+
end
|
176
|
+
|
177
|
+
sleep 0.01
|
178
|
+
|
179
|
+
@results << :before_secondary
|
180
|
+
token2.get('/200')
|
181
|
+
@results << :after_secondary
|
182
|
+
|
183
|
+
new_thread.join
|
184
|
+
assert_equal [:before_primary, :before_secondary, :after_primary, :after_secondary], @results
|
185
|
+
assert_requested(stub_refresh)
|
186
|
+
end
|
187
|
+
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: access_token_wrapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bradley Priest
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: webmock
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -70,8 +70,11 @@ files:
|
|
70
70
|
- access_token_wrapper.gemspec
|
71
71
|
- lib/access_token_wrapper.rb
|
72
72
|
- lib/access_token_wrapper/base.rb
|
73
|
+
- lib/access_token_wrapper/configuration.rb
|
74
|
+
- lib/access_token_wrapper/from_record.rb
|
73
75
|
- lib/access_token_wrapper/version.rb
|
74
76
|
- test/base_test.rb
|
77
|
+
- test/from_record_test.rb
|
75
78
|
- test/test_helper.rb
|
76
79
|
homepage: https://github.com/tradegecko/access_token_wrapper
|
77
80
|
licenses:
|
@@ -92,12 +95,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
95
|
- !ruby/object:Gem::Version
|
93
96
|
version: '0'
|
94
97
|
requirements: []
|
95
|
-
|
96
|
-
rubygems_version: 2.6.13
|
98
|
+
rubygems_version: 3.1.2
|
97
99
|
signing_key:
|
98
100
|
specification_version: 4
|
99
101
|
summary: Wrapper for OAuth2::Token to automatically refresh the expiry token when
|
100
102
|
expired.
|
101
103
|
test_files:
|
102
104
|
- test/base_test.rb
|
105
|
+
- test/from_record_test.rb
|
103
106
|
- test/test_helper.rb
|