oauth2_api_client 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 19c17dc8d34436a95460c68a49a070600cc70cccb68336bb58c47ea10ec42efb
4
+ data.tar.gz: bfe18b660c1f56ed84ef4d26a9b277acb1bd3a50b135196b89988a4a676a0ff7
5
+ SHA512:
6
+ metadata.gz: 77f3e27e9d04b09ced28691dc76a48d3f00a47c76d8a6fbdd847bbb45097cc562dff75da161b25f4a2f39e84578aa361c41e24cb6ecb19a6a329b13f9685c899
7
+ data.tar.gz: 5917eb46b4d65536d2246597774734d8c6b815245c9babfa8818f0b76f289c5d415ddb60066e9af4cbf96821d7d16c821c125936c2476daf1399d763cfe31175
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ gemfiles/*.lock
19
+ irb.rb
@@ -0,0 +1,125 @@
1
+ AllCops:
2
+ NewCops: enable
3
+
4
+ Metrics/ParameterLists:
5
+ Enabled: false
6
+
7
+ Style/HashTransformValues:
8
+ Enabled: false
9
+
10
+ Style/HashTransformKeys:
11
+ Enabled: false
12
+
13
+ Style/HashEachMethods:
14
+ Enabled: true
15
+
16
+ Style/FrozenStringLiteralComment:
17
+ Enabled: false
18
+
19
+ Lint/RedundantRequireStatement:
20
+ Enabled: false
21
+
22
+ Layout/ArgumentAlignment:
23
+ EnforcedStyle: with_fixed_indentation
24
+
25
+ Layout/FirstArrayElementIndentation:
26
+ EnforcedStyle: consistent
27
+
28
+ Style/PercentLiteralDelimiters:
29
+ Enabled: false
30
+
31
+ Style/SpecialGlobalVars:
32
+ EnforcedStyle: use_english_names
33
+
34
+ Security/Eval:
35
+ Enabled: false
36
+
37
+ Style/WordArray:
38
+ EnforcedStyle: brackets
39
+
40
+ Style/ClassAndModuleChildren:
41
+ Enabled: false
42
+
43
+ Style/TrivialAccessors:
44
+ Enabled: false
45
+
46
+ Style/Alias:
47
+ Enabled: false
48
+
49
+ Style/StringLiteralsInInterpolation:
50
+ EnforcedStyle: double_quotes
51
+
52
+ Metrics/ClassLength:
53
+ Enabled: false
54
+
55
+ Naming/MethodParameterName:
56
+ Enabled: false
57
+
58
+ Style/SymbolArray:
59
+ EnforcedStyle: brackets
60
+
61
+ Layout/RescueEnsureAlignment:
62
+ Enabled: false
63
+
64
+ Layout/LineLength:
65
+ Enabled: false
66
+
67
+ Metrics/MethodLength:
68
+ Enabled: false
69
+
70
+ Metrics/ModuleLength:
71
+ Enabled: false
72
+
73
+ Style/ZeroLengthPredicate:
74
+ Enabled: false
75
+
76
+ Metrics/PerceivedComplexity:
77
+ Enabled: false
78
+
79
+ Metrics/AbcSize:
80
+ Enabled: false
81
+
82
+ Metrics/CyclomaticComplexity:
83
+ Enabled: false
84
+
85
+ Metrics/BlockLength:
86
+ Enabled: false
87
+
88
+ Metrics/BlockNesting:
89
+ Enabled: false
90
+
91
+ Style/NumericPredicate:
92
+ Enabled: false
93
+
94
+ Naming/AccessorMethodName:
95
+ Enabled: false
96
+
97
+ Naming/MemoizedInstanceVariableName:
98
+ Enabled: false
99
+
100
+ Style/StringLiterals:
101
+ EnforcedStyle: double_quotes
102
+
103
+ Style/Documentation:
104
+ Enabled: false
105
+
106
+ Naming/ConstantName:
107
+ Enabled: false
108
+
109
+ Style/MutableConstant:
110
+ Enabled: false
111
+
112
+ Layout/MultilineMethodCallIndentation:
113
+ EnforcedStyle: indented
114
+
115
+ Layout/ParameterAlignment:
116
+ EnforcedStyle: with_fixed_indentation
117
+
118
+ Lint/UnusedMethodArgument:
119
+ Enabled: false
120
+
121
+ Style/IfUnlessModifier:
122
+ Enabled: false
123
+
124
+ Style/RedundantBegin:
125
+ Enabled: false
@@ -0,0 +1,10 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - ruby-2.6.2
5
+ - ruby-2.7.1
6
+ install:
7
+ - travis_retry bundle install
8
+ script:
9
+ - bundle exec rspec
10
+ - bundle exec rubocop
@@ -0,0 +1,3 @@
1
+
2
+ # CHANGELOG
3
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Benjamin Vetter
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,61 @@
1
+ # oauth2_api_client
2
+
3
+ [![Build Status](https://secure.travis-ci.org/mrkamel/oauth2_api_client.svg?branch=master)](http://travis-ci.org/mrkamel/oauth2_api_client)
4
+ [![Gem Version](https://badge.fury.io/rb/oauth2_api_client.svg)](http://badge.fury.io/rb/oauth2_api_client)
5
+
6
+ Oauth2ApiClient is small, but powerful client around
7
+ [oauth2](https://github.com/oauth-xx/oauth2) and
8
+ [http-rb](https://github.com/httprb/http) to interact with APIs which use
9
+ oauth2 for authentication with automatic token caching and renewal.
10
+
11
+ ```ruby
12
+ client = Oauth2ApiClient.new(
13
+ base_url: "https://api.example.com/",
14
+ client_id: "the client id",
15
+ client_secret: "the client secret",
16
+ oauth_token_url: "https://auth.example.com/oauth2/token",
17
+ max_token_ttl: 3600, # optional
18
+ cache: Rails.cache # optional
19
+ )
20
+
21
+ client.post("/orders", json: { address: "..." }).status.success?
22
+ client.headers("User-Agent" => "API Client").timeout(read: 5, write: 5).get("/orders").parse
23
+ # ...
24
+ ```
25
+
26
+ ## Install
27
+
28
+ Add this line to your application's Gemfile:
29
+
30
+ ```ruby
31
+ gem 'oauth2_api_client'
32
+ ```
33
+
34
+ and then execute
35
+
36
+ ```
37
+ $ bundle
38
+ ```
39
+
40
+ or install it via
41
+
42
+ ```
43
+ $ gem install oauth2_api_client
44
+ ```
45
+
46
+ ## Reference Docs
47
+
48
+ The reference docs can be found at
49
+ [http://www.rubydoc.info/github/mrkamel/oauth2_api_client](http://www.rubydoc.info/github/mrkamel/oauth2_api_client)
50
+
51
+ ## Semantic Versioning
52
+
53
+ Oauth2ApiClient is using Semantic Versioning: [SemVer](http://semver.org/)
54
+
55
+ ## Contributing
56
+
57
+ 1. Fork it
58
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
59
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
60
+ 4. Push to the branch (`git push origin my-new-feature`)
61
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "lib"
6
+ t.pattern = "test/**/*_test.rb"
7
+ t.verbose = true
8
+ end
@@ -0,0 +1,117 @@
1
+ require "ruby2_keywords"
2
+ require "oauth2"
3
+ require "http"
4
+ require "ruby2_keywords"
5
+ require "active_support"
6
+
7
+ require "oauth2_api_client/version"
8
+ require "oauth2_api_client/http_error"
9
+
10
+ # The Oauth2ApiClient class is a client wrapped around the oauth2 and http-rb
11
+ # gem to interact with APIs using oauth2 for authentication with automatic
12
+ # token caching and renewal.
13
+
14
+ class Oauth2ApiClient
15
+ # Creates a new Oauth2ApiClient
16
+ #
17
+ # @param base_url [String] The base url of the API to interact with
18
+ # @param client_id [String] The client id to use for oauth2 authentication
19
+ # @param client_secret [String] The client secret to use for oauth2 authentication
20
+ # @param oauth_token_url [String] The url to obtain tokens from
21
+ # @param cache The cache instance to cache the tokens, e.g. `Rails.cache`.
22
+ # Defaults to `ActiveSupport::Cache::MemoryStore.new`
23
+ # @param max_token_ttl [#to_i] The max lifetime of the token in the cache
24
+ # @param base_request You can pass some http-rb rqeuest as the base. Useful,
25
+ # if some information needs to be passed with every request. Defaults to
26
+ # `HTTP`
27
+ #
28
+ # @example
29
+ # client = Oauth2ApiClient.new(
30
+ # base_url: "https://api.example.com/",
31
+ # client_id: "the client id",
32
+ # client_secret: "the client secret",
33
+ # oauth_token_url: "https://auth.example.com/oauth2/token",
34
+ # cache: Rails.cache,
35
+ # base_request: HTTP.headers("User-Agent" => "API client")
36
+ # )
37
+ #
38
+ # client.post("/orders", json: { address: "..." }).status.success?
39
+ # client.headers("User-Agent" => "API Client").timeout(read: 5, write: 5).get("/orders").parse
40
+
41
+ def initialize(base_url:, client_id:, client_secret:, oauth_token_url:, cache: ActiveSupport::Cache::MemoryStore.new, max_token_ttl: 3600, base_request: HTTP)
42
+ @base_url = base_url
43
+ @client_id = client_id
44
+ @client_secret = client_secret
45
+ @oauth_token_url = oauth_token_url
46
+ @max_token_ttl = max_token_ttl
47
+ @cache = cache
48
+ @request = base_request
49
+
50
+ oauth_uri = URI.parse(oauth_token_url)
51
+
52
+ @oauth_client = OAuth2::Client.new(
53
+ @client_id,
54
+ @client_secret,
55
+ site: URI.parse("#{oauth_uri.scheme}://#{oauth_uri.host}:#{oauth_uri.port}/").to_s,
56
+ token_url: oauth_uri.path
57
+ )
58
+ end
59
+
60
+ # Returns a oauth2 token to use for authentication
61
+ #
62
+ # @return [String] The token
63
+
64
+ def token
65
+ @cache.fetch(cache_key, expires_in: @max_token_ttl.to_i) do
66
+ @oauth_client.client_credentials.get_token.token
67
+ end
68
+ end
69
+
70
+ [:timeout, :headers, :cookies, :via, :encoding, :accept, :auth, :basic_auth].each do |method|
71
+ define_method method do |*args|
72
+ dup.tap do |client|
73
+ client.instance_variable_set(:@request, @request.send(method, *args))
74
+ end
75
+ end
76
+
77
+ ruby2_keywords method
78
+ end
79
+
80
+ [:get, :post, :put, :delete, :head, :options].each do |method|
81
+ define_method method do |path, options = {}|
82
+ execute(method, path, options)
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def cache_key
89
+ @cache_key ||= ["oauth_api_client", @base_url, @oauth_token_url, @client_id].join("|")
90
+ end
91
+
92
+ def execute(verb, path, options = {})
93
+ with_retry do
94
+ response = @request.auth("Bearer #{token}").send(verb, URI.join(@base_url, path), options)
95
+
96
+ return response if response.status.success?
97
+
98
+ raise HttpError.new(response.status.to_s, response)
99
+ end
100
+ end
101
+
102
+ def with_retry
103
+ retried = false
104
+
105
+ begin
106
+ yield
107
+ rescue HttpError => e
108
+ @cache.delete(cache_key) if e.response.status.unauthorized?
109
+
110
+ raise(e) if retried || !e.response.status.unauthorized?
111
+
112
+ retried = true
113
+
114
+ retry
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,10 @@
1
+ class Oauth2ApiClient
2
+ class HttpError < StandardError
3
+ attr_reader :message, :response
4
+
5
+ def initialize(message, response)
6
+ @message = message
7
+ @response = response
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ class Oauth2ApiClient
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,31 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require "oauth2_api_client/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "oauth2_api_client"
8
+ spec.version = Oauth2ApiClient::VERSION
9
+ spec.authors = ["Benjamin Vetter"]
10
+ spec.email = ["vetter@flakks.com"]
11
+ spec.description = "Small but powerful client around oauth2 and http-rb to interact with APIs"
12
+ spec.summary = "Small but powerful client around oauth2 and http-rb to interact with APIs"
13
+ spec.homepage = "https://github.com/mrkamel/oauth2_api_client"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency "rubocop"
24
+ spec.add_development_dependency "timecop"
25
+ spec.add_development_dependency "webmock"
26
+
27
+ spec.add_dependency "activesupport"
28
+ spec.add_dependency "http"
29
+ spec.add_dependency "oauth2"
30
+ spec.add_dependency "ruby2_keywords"
31
+ end
@@ -0,0 +1,193 @@
1
+ require File.expand_path("./spec_helper", __dir__)
2
+
3
+ class HttpTestRequest
4
+ attr_accessor :calls
5
+
6
+ def initialize
7
+ self.calls = []
8
+ end
9
+
10
+ [:timeout, :headers, :cookies, :via, :encoding, :accept, :auth, :basic_auth].each do |method|
11
+ define_method method do |*args|
12
+ dup.tap do |request|
13
+ request.calls = calls + [[method, args]]
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ RSpec.describe Oauth2ApiClient do
20
+ before do
21
+ token_response = {
22
+ access_token: "access_token",
23
+ token_type: "bearer",
24
+ expires_in: 3600,
25
+ refresh_token: "refresh_token",
26
+ scope: "create"
27
+ }
28
+
29
+ stub_request(:post, "http://localhost/oauth2/token")
30
+ .to_return(status: 200, body: JSON.generate(token_response), headers: { "Content-Type" => "application/json" })
31
+ end
32
+
33
+ describe "#token" do
34
+ it "returns a oauth2 token" do
35
+ client = described_class.new(
36
+ base_url: "http://localhost/",
37
+ client_id: "client_id",
38
+ client_secret: "client_secret",
39
+ oauth_token_url: "http://localhost/oauth2/token"
40
+ )
41
+
42
+ expect(client.token).to eq("access_token")
43
+ end
44
+
45
+ it "returns the cached token if existing" do
46
+ cache = ActiveSupport::Cache::MemoryStore.new
47
+
48
+ allow(cache).to receive(:fetch).and_return("cached_token")
49
+
50
+ client = described_class.new(
51
+ base_url: "http://localhost/",
52
+ client_id: "client_id",
53
+ client_secret: "client_secret",
54
+ oauth_token_url: "http://localhost/oauth2/token",
55
+ cache: cache
56
+ )
57
+
58
+ expect(client.token).to eq("cached_token")
59
+ end
60
+
61
+ it "caches the token" do
62
+ cache = ActiveSupport::Cache::MemoryStore.new
63
+
64
+ allow(cache).to receive(:fetch).and_yield
65
+
66
+ client = described_class.new(
67
+ base_url: "http://localhost/",
68
+ client_id: "client_id",
69
+ client_secret: "client_secret",
70
+ oauth_token_url: "http://localhost/oauth2/token",
71
+ max_token_ttl: 60,
72
+ cache: cache
73
+ )
74
+
75
+ client.token
76
+
77
+ expect(cache).to have_received(:fetch).with("oauth_api_client|http://localhost/|http://localhost/oauth2/token|client_id", expires_in: 60)
78
+ end
79
+ end
80
+
81
+ [:timeout, :headers, :cookies, :via, :encoding, :accept, :auth, :basic_auth].each do |method|
82
+ describe "##{method}" do
83
+ it "creates a dupped instance" do
84
+ client = described_class.new(
85
+ base_url: "http://localhost/",
86
+ client_id: "client_id",
87
+ client_secret: "client_secret",
88
+ oauth_token_url: "http://localhost/oauth2/token",
89
+ base_request: HttpTestRequest.new
90
+ )
91
+
92
+ client1 = client.send(method, "key1")
93
+ client2 = client1.send(method, "key1")
94
+
95
+ expect(client1.object_id).not_to eq(client2.object_id)
96
+ end
97
+
98
+ it "extends the request" do
99
+ client = described_class.new(
100
+ base_url: "http://localhost/",
101
+ client_id: "client_id",
102
+ client_secret: "client_secret",
103
+ oauth_token_url: "http://localhost/oauth2/token",
104
+ base_request: HttpTestRequest.new
105
+ )
106
+
107
+ client1 = client.send(method, "key1")
108
+ client2 = client1.send(method, "key2")
109
+
110
+ expect(client1.instance_variable_get(:@request).calls).to eq([[method, ["key1"]]])
111
+ expect(client2.instance_variable_get(:@request).calls).to eq([[method, ["key1"]], [method, ["key2"]]])
112
+ end
113
+ end
114
+ end
115
+
116
+ describe "request" do
117
+ it "prepends the base url" do
118
+ stub_request(:get, "http://localhost/path?key=value")
119
+ .to_return(status: 200, body: "ok")
120
+
121
+ client = described_class.new(
122
+ base_url: "http://localhost/",
123
+ client_id: "client_id",
124
+ client_secret: "client_secret",
125
+ oauth_token_url: "http://localhost/oauth2/token"
126
+ )
127
+
128
+ expect(client.get("/path", params: { key: "value" }).to_s).to eq("ok")
129
+ end
130
+
131
+ it "passes the token in the authentication header" do
132
+ stub_request(:get, "http://localhost/path")
133
+ .with(headers: { "Authorization" => "Bearer access_token" })
134
+ .to_return(status: 200, body: "ok", headers: {})
135
+
136
+ client = described_class.new(
137
+ base_url: "http://localhost/",
138
+ client_id: "client_id",
139
+ client_secret: "client_secret",
140
+ oauth_token_url: "http://localhost/oauth2/token"
141
+ )
142
+
143
+ expect(client.get("/path").to_s).to eq("ok")
144
+ end
145
+
146
+ it "invalidates the cached token when an http unauthorized status is returned" do
147
+ stub_request(:get, "http://localhost/path")
148
+ .to_return(status: 401, body: "unauthorized")
149
+
150
+ cache = ActiveSupport::Cache::MemoryStore.new
151
+
152
+ client = described_class.new(
153
+ base_url: "http://localhost/",
154
+ client_id: "client_id",
155
+ client_secret: "client_secret",
156
+ oauth_token_url: "http://localhost/oauth2/token",
157
+ cache: cache
158
+ )
159
+
160
+ expect { client.get("/path") }.to raise_error(described_class::HttpError)
161
+
162
+ expect(cache.read("oauth_api_client|http://localhost/|http://localhost/oauth2/token|client_id")).to be_nil
163
+ end
164
+
165
+ it "retries the request when an http unauthorized status is returned" do
166
+ stub_request(:get, "http://localhost/path")
167
+ .to_return({ status: 401, body: "unauthorized" }, { status: 200, body: "ok" })
168
+
169
+ client = described_class.new(
170
+ base_url: "http://localhost/",
171
+ client_id: "client_id",
172
+ client_secret: "client_secret",
173
+ oauth_token_url: "http://localhost/oauth2/token"
174
+ )
175
+
176
+ expect(client.get("/path").to_s).to eq("ok")
177
+ end
178
+
179
+ it "raises if the retried request also fails" do
180
+ stub_request(:get, "http://localhost/path")
181
+ .to_return(status: 401, body: "unauthorized")
182
+
183
+ client = described_class.new(
184
+ base_url: "http://localhost/",
185
+ client_id: "client_id",
186
+ client_secret: "client_secret",
187
+ oauth_token_url: "http://localhost/oauth2/token"
188
+ )
189
+
190
+ expect { client.get("/path") }.to raise_error(described_class::HttpError)
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,5 @@
1
+ require "oauth2_api_client"
2
+ require "webmock/rspec"
3
+ require "timecop"
4
+
5
+ WebMock.disable_net_connect!
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oauth2_api_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Benjamin Vetter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-06-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: timecop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activesupport
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: http
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: oauth2
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: ruby2_keywords
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Small but powerful client around oauth2 and http-rb to interact with
140
+ APIs
141
+ email:
142
+ - vetter@flakks.com
143
+ executables: []
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".gitignore"
148
+ - ".rubocop.yml"
149
+ - ".travis.yml"
150
+ - CHANGELOG.md
151
+ - Gemfile
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - lib/oauth2_api_client.rb
156
+ - lib/oauth2_api_client/http_error.rb
157
+ - lib/oauth2_api_client/version.rb
158
+ - oauth2_api_client.gemspec
159
+ - spec/oauth2_api_client_spec.rb
160
+ - spec/spec_helper.rb
161
+ homepage: https://github.com/mrkamel/oauth2_api_client
162
+ licenses:
163
+ - MIT
164
+ metadata: {}
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubygems_version: 3.0.3
181
+ signing_key:
182
+ specification_version: 4
183
+ summary: Small but powerful client around oauth2 and http-rb to interact with APIs
184
+ test_files:
185
+ - spec/oauth2_api_client_spec.rb
186
+ - spec/spec_helper.rb