access_token_wrapper 0.2.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|