omniauth-quickbooks-oauth2-modern 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be89aee453817eeae8a1010d880f1e3573dc56355347c29211f4b2b535e25c4d
4
- data.tar.gz: 217a086f82719d772996ab2c267f5015718abb6522f4e0daf28a31a50b07e5eb
3
+ metadata.gz: b34af49e6a0c3fb18416a2f2375d4de6fbc9a8db55277776320c9b21aa0e44f3
4
+ data.tar.gz: 2cd785029a2b9a26fc7f3bdfe8fc5b716d6aeafab47e1ffeb297d7b0b837a1c7
5
5
  SHA512:
6
- metadata.gz: 3b866eb508a50c13f73ab54fafaddc423caf683cc44c272c41c4283300e627c8c29be457b89e49c1ba09916c48681db94705fbdd34212e57f0a70a0117d32b73
7
- data.tar.gz: 0f880dcb6684f6d2818b3be82c44b3dbd097a26ccf5460238ca10b40b6cb2fc3e7305d7ea663db7262eb43333e4f356cb5f2886ddc035f6f3d82b42187401c46
6
+ metadata.gz: d411ec48a52dc0fb5f064273778025676637aab84e8c008d1127b342c5a60f834f539548cbaf955027bc7a2df7457dea6839f51799ee65611046c3eac9f77094
7
+ data.tar.gz: '09794199b6e906a18fd2091437262e1ea1a903ccced8347271bed6adb719f1925b43940c335fc1246a96ba85f674072450a7608f6a6d02e34c12690aa041d098'
data/.rubocop.yml CHANGED
@@ -1,9 +1,11 @@
1
+ require:
2
+ - rubocop-rspec
3
+
1
4
  AllCops:
2
5
  TargetRubyVersion: 3.0
3
6
  NewCops: enable
4
7
  Exclude:
5
8
  - "vendor/**/*"
6
- - "spec/**/*"
7
9
 
8
10
  Style/Documentation:
9
11
  Enabled: false
@@ -12,3 +14,49 @@ Metrics/BlockLength:
12
14
  Exclude:
13
15
  - "spec/**/*"
14
16
  - "*.gemspec"
17
+
18
+ Metrics/ClassLength:
19
+ Max: 150
20
+
21
+ Metrics/MethodLength:
22
+ Max: 25
23
+
24
+ Metrics/AbcSize:
25
+ Max: 25
26
+
27
+ Gemspec/DevelopmentDependencies:
28
+ Enabled: false
29
+
30
+ RSpec/SubjectStub:
31
+ Enabled: false
32
+
33
+ RSpec/VerifiedDoubles:
34
+ Enabled: false
35
+
36
+ RSpec/FilePath:
37
+ Enabled: false
38
+
39
+ RSpec/SpecFilePathFormat:
40
+ Enabled: false
41
+
42
+ RSpec/MultipleExpectations:
43
+ Max: 5
44
+
45
+ RSpec/ExampleLength:
46
+ Max: 15
47
+
48
+ RSpec/NestedGroups:
49
+ Max: 5
50
+
51
+ RSpec/MessageSpies:
52
+ Enabled: false
53
+
54
+ RSpec/DescribedClass:
55
+ Enabled: false
56
+
57
+ Naming/FileName:
58
+ Exclude:
59
+ - 'lib/omniauth-quickbooks-oauth2-modern.rb'
60
+
61
+ Metrics/ParameterLists:
62
+ Max: 8
data/CHANGELOG.md CHANGED
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.0] - 2026-01-31
9
+
10
+ ### Added
11
+
12
+ - TokenClient class for easy token refresh in Rails apps
13
+ - `refresh_token` method with result object pattern
14
+ - `token_expired?` helper with configurable buffer
15
+ - Comprehensive RSpec tests for TokenClient (26 new tests)
16
+
8
17
  ## [1.0.0] - 2026-01-31
9
18
 
10
19
  ### Added
data/README.md CHANGED
@@ -201,6 +201,102 @@ def self.from_omniauth(auth)
201
201
  end
202
202
  ```
203
203
 
204
+ ## Token Refresh
205
+
206
+ This gem includes a `TokenClient` class to easily refresh tokens in your Rails app.
207
+
208
+ ### Basic Usage
209
+
210
+ ```ruby
211
+ # Create a client instance
212
+ client = OmniAuth::QuickbooksOauth2Modern::TokenClient.new(
213
+ client_id: ENV['QBO_CLIENT_ID'],
214
+ client_secret: ENV['QBO_CLIENT_SECRET']
215
+ )
216
+
217
+ # Refresh an expired token
218
+ result = client.refresh_token(account.qbo_refresh_token)
219
+
220
+ if result.success?
221
+ account.update!(
222
+ qbo_access_token: result.access_token,
223
+ qbo_refresh_token: result.refresh_token,
224
+ qbo_token_expires_at: Time.at(result.expires_at)
225
+ )
226
+ else
227
+ Rails.logger.error "Token refresh failed: #{result.error}"
228
+ end
229
+ ```
230
+
231
+ ### Check Token Expiration
232
+
233
+ ```ruby
234
+ # Check if token is expired (with 5-minute buffer by default)
235
+ client.token_expired?(account.qbo_token_expires_at)
236
+
237
+ # Custom buffer (e.g., refresh 1 hour before expiry)
238
+ client.token_expired?(account.qbo_token_expires_at, buffer_seconds: 3600)
239
+ ```
240
+
241
+ ### Rails Service Example
242
+
243
+ ```ruby
244
+ # app/services/quickbooks_api_service.rb
245
+ class QuickBooksApiService
246
+ def initialize(account)
247
+ @account = account
248
+ @client = OmniAuth::QuickbooksOauth2Modern::TokenClient.new(
249
+ client_id: ENV['QBO_CLIENT_ID'],
250
+ client_secret: ENV['QBO_CLIENT_SECRET']
251
+ )
252
+ end
253
+
254
+ def with_valid_token
255
+ refresh_if_expired!
256
+ yield @account.qbo_access_token
257
+ end
258
+
259
+ private
260
+
261
+ def refresh_if_expired!
262
+ return unless @client.token_expired?(@account.qbo_token_expires_at)
263
+
264
+ result = @client.refresh_token(@account.qbo_refresh_token)
265
+ raise "Token refresh failed: #{result.error}" unless result.success?
266
+
267
+ @account.update!(
268
+ qbo_access_token: result.access_token,
269
+ qbo_refresh_token: result.refresh_token,
270
+ qbo_token_expires_at: Time.at(result.expires_at)
271
+ )
272
+ end
273
+ end
274
+
275
+ # Usage
276
+ QuickBooksApiService.new(current_account).with_valid_token do |token|
277
+ # Make API calls with valid token
278
+ response = Faraday.get("https://quickbooks.api.intuit.com/v3/company/#{realm_id}/query") do |req|
279
+ req.headers['Authorization'] = "Bearer #{token}"
280
+ req.params['query'] = "SELECT * FROM Customer"
281
+ end
282
+ end
283
+ ```
284
+
285
+ ### TokenResult Object
286
+
287
+ The `refresh_token` method returns a `TokenResult` object with:
288
+
289
+ | Method | Description |
290
+ |--------|-------------|
291
+ | `success?` | Returns `true` if refresh succeeded |
292
+ | `failure?` | Returns `true` if refresh failed |
293
+ | `access_token` | The new access token |
294
+ | `refresh_token` | The new refresh token |
295
+ | `expires_at` | Unix timestamp when token expires |
296
+ | `expires_in` | Seconds until token expires |
297
+ | `error` | Error message if failed |
298
+ | `raw_response` | Full response hash from Intuit |
299
+
204
300
  ## Scopes
205
301
 
206
302
  Common QuickBooks scopes:
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- require "rubocop/rake_task"
8
+ require 'rubocop/rake_task'
9
9
  RuboCop::RakeTask.new
10
10
 
11
11
  task default: %i[spec rubocop]
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+ require 'base64'
6
+
7
+ module OmniAuth
8
+ module QuickbooksOauth2Modern
9
+ # Client for managing QuickBooks OAuth2 tokens
10
+ #
11
+ # This class provides an easy way to refresh expired tokens in your Rails app.
12
+ #
13
+ # @example Basic usage
14
+ # client = OmniAuth::QuickbooksOauth2Modern::TokenClient.new(
15
+ # client_id: ENV['QBO_CLIENT_ID'],
16
+ # client_secret: ENV['QBO_CLIENT_SECRET']
17
+ # )
18
+ #
19
+ # # Refresh an expired token
20
+ # result = client.refresh_token(user.qbo_refresh_token)
21
+ # if result.success?
22
+ # user.update!(
23
+ # qbo_access_token: result.access_token,
24
+ # qbo_refresh_token: result.refresh_token,
25
+ # qbo_token_expires_at: result.expires_at
26
+ # )
27
+ # end
28
+ #
29
+ # @example With automatic token refresh in a service
30
+ # class QuickBooksApiService
31
+ # def initialize(account)
32
+ # @account = account
33
+ # @client = OmniAuth::QuickbooksOauth2Modern::TokenClient.new(
34
+ # client_id: ENV['QBO_CLIENT_ID'],
35
+ # client_secret: ENV['QBO_CLIENT_SECRET']
36
+ # )
37
+ # end
38
+ #
39
+ # def with_valid_token
40
+ # refresh_if_expired!
41
+ # yield @account.access_token
42
+ # end
43
+ #
44
+ # private
45
+ #
46
+ # def refresh_if_expired!
47
+ # return unless @client.token_expired?(@account.token_expires_at)
48
+ #
49
+ # result = @client.refresh_token(@account.refresh_token)
50
+ # raise "Token refresh failed: #{result.error}" unless result.success?
51
+ #
52
+ # @account.update!(
53
+ # access_token: result.access_token,
54
+ # refresh_token: result.refresh_token,
55
+ # token_expires_at: result.expires_at
56
+ # )
57
+ # end
58
+ # end
59
+ #
60
+ class TokenClient
61
+ # Result object for token operations
62
+ class TokenResult
63
+ attr_reader :access_token, :refresh_token, :expires_at, :expires_in, :error, :raw_response
64
+
65
+ def initialize(success:, access_token: nil, refresh_token: nil, expires_at: nil, expires_in: nil,
66
+ error: nil, raw_response: nil)
67
+ @success = success
68
+ @access_token = access_token
69
+ @refresh_token = refresh_token
70
+ @expires_at = expires_at
71
+ @expires_in = expires_in
72
+ @error = error
73
+ @raw_response = raw_response
74
+ end
75
+
76
+ def success?
77
+ @success
78
+ end
79
+
80
+ def failure?
81
+ !@success
82
+ end
83
+ end
84
+
85
+ # Intuit OAuth2 token endpoint
86
+ TOKEN_URL = 'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer'
87
+
88
+ attr_reader :client_id, :client_secret
89
+
90
+ # Initialize a new TokenClient
91
+ #
92
+ # @param client_id [String] Your QuickBooks App Client ID
93
+ # @param client_secret [String] Your QuickBooks App Client Secret
94
+ def initialize(client_id:, client_secret:)
95
+ @client_id = client_id
96
+ @client_secret = client_secret
97
+ end
98
+
99
+ # Refresh an access token using a refresh token
100
+ #
101
+ # @param refresh_token [String] The refresh token to use
102
+ # @return [TokenResult] Result object with new tokens or error
103
+ def refresh_token(refresh_token)
104
+ if refresh_token.nil? || refresh_token.empty?
105
+ return TokenResult.new(success: false,
106
+ error: 'Refresh token is required')
107
+ end
108
+
109
+ response = make_refresh_request(refresh_token)
110
+
111
+ if response.success?
112
+ parse_success_response(response)
113
+ else
114
+ parse_error_response(response)
115
+ end
116
+ rescue Faraday::Error => e
117
+ TokenResult.new(success: false, error: "Network error: #{e.message}")
118
+ rescue JSON::ParserError => e
119
+ TokenResult.new(success: false, error: "Invalid JSON response: #{e.message}")
120
+ rescue StandardError => e
121
+ TokenResult.new(success: false, error: "Unexpected error: #{e.message}")
122
+ end
123
+
124
+ # Check if a token is expired or about to expire
125
+ #
126
+ # @param expires_at [Time, Integer] Token expiration time
127
+ # @param buffer_seconds [Integer] Buffer before expiration (default: 300 = 5 minutes)
128
+ # @return [Boolean] True if token is expired or will expire within buffer
129
+ def token_expired?(expires_at, buffer_seconds: 300)
130
+ return true if expires_at.nil?
131
+
132
+ expires_at_time = expires_at.is_a?(Integer) ? Time.at(expires_at) : expires_at
133
+ Time.now >= (expires_at_time - buffer_seconds)
134
+ end
135
+
136
+ private
137
+
138
+ def make_refresh_request(refresh_token)
139
+ # QuickBooks uses Basic Auth with base64 encoded client_id:client_secret
140
+ credentials = Base64.strict_encode64("#{client_id}:#{client_secret}")
141
+
142
+ Faraday.post(TOKEN_URL) do |req|
143
+ req.headers['Authorization'] = "Basic #{credentials}"
144
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
145
+ req.headers['Accept'] = 'application/json'
146
+ req.body = URI.encode_www_form(
147
+ grant_type: 'refresh_token',
148
+ refresh_token: refresh_token
149
+ )
150
+ end
151
+ end
152
+
153
+ def parse_success_response(response)
154
+ data = JSON.parse(response.body)
155
+
156
+ expires_in = data['expires_in']&.to_i
157
+ expires_at = expires_in ? Time.now.to_i + expires_in : nil
158
+
159
+ TokenResult.new(
160
+ success: true,
161
+ access_token: data['access_token'],
162
+ refresh_token: data['refresh_token'],
163
+ expires_in: expires_in,
164
+ expires_at: expires_at,
165
+ raw_response: data
166
+ )
167
+ end
168
+
169
+ def parse_error_response(response)
170
+ error_data = begin
171
+ JSON.parse(response.body)
172
+ rescue JSON::ParserError
173
+ { 'error' => response.body }
174
+ end
175
+
176
+ error_message = error_data['error_description'] || error_data['error'] || "HTTP #{response.status}"
177
+
178
+ TokenResult.new(
179
+ success: false,
180
+ error: error_message,
181
+ raw_response: error_data
182
+ )
183
+ end
184
+ end
185
+ end
186
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OmniAuth
4
4
  module QuickbooksOauth2Modern
5
- VERSION = "1.0.0"
5
+ VERSION = '1.1.0'
6
6
  end
7
7
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omniauth-oauth2"
4
- require "faraday"
5
- require "json"
3
+ require 'omniauth-oauth2'
4
+ require 'faraday'
5
+ require 'json'
6
6
 
7
7
  module OmniAuth
8
8
  module Strategies
@@ -24,15 +24,15 @@ module OmniAuth
24
24
  option :name, :quickbooks_oauth2_modern
25
25
 
26
26
  # Default scopes for QuickBooks accounting access with OpenID
27
- option :scope, "com.intuit.quickbooks.accounting openid profile email"
27
+ option :scope, 'com.intuit.quickbooks.accounting openid profile email'
28
28
 
29
29
  # Sandbox mode (default: true for safety)
30
30
  option :sandbox, true
31
31
 
32
32
  option :client_options, {
33
- site: "https://appcenter.intuit.com",
34
- authorize_url: "/connect/oauth2",
35
- token_url: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
33
+ site: 'https://appcenter.intuit.com',
34
+ authorize_url: '/connect/oauth2',
35
+ token_url: 'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer'
36
36
  }
37
37
 
38
38
  # Use realmId (company ID) as the unique identifier
@@ -40,20 +40,20 @@ module OmniAuth
40
40
 
41
41
  info do
42
42
  {
43
- email: raw_info["email"],
44
- first_name: raw_info["givenName"],
45
- last_name: raw_info["familyName"],
43
+ email: raw_info['email'],
44
+ first_name: raw_info['givenName'],
45
+ last_name: raw_info['familyName'],
46
46
  name: full_name,
47
- phone: raw_info["phoneNumber"],
47
+ phone: raw_info['phoneNumber'],
48
48
  realm_id: realm_id
49
49
  }
50
50
  end
51
51
 
52
52
  credentials do
53
- hash = { "token" => access_token.token }
54
- hash["refresh_token"] = access_token.refresh_token if access_token.refresh_token
55
- hash["expires_at"] = access_token.expires_at if access_token.expires_at
56
- hash["expires"] = access_token.expires?
53
+ hash = { 'token' => access_token.token }
54
+ hash['refresh_token'] = access_token.refresh_token if access_token.refresh_token
55
+ hash['expires_at'] = access_token.expires_at if access_token.expires_at
56
+ hash['expires'] = access_token.expires?
57
57
  hash
58
58
  end
59
59
 
@@ -78,12 +78,12 @@ module OmniAuth
78
78
 
79
79
  # The QuickBooks company ID (realmId)
80
80
  def realm_id
81
- request.params["realmId"]
81
+ request.params['realmId']
82
82
  end
83
83
 
84
84
  # Construct full name from OpenID info
85
85
  def full_name
86
- name = [raw_info["givenName"], raw_info["familyName"]].compact.join(" ")
86
+ name = [raw_info['givenName'], raw_info['familyName']].compact.join(' ')
87
87
  name.empty? ? nil : name
88
88
  end
89
89
 
@@ -101,13 +101,13 @@ module OmniAuth
101
101
 
102
102
  # Check if OpenID scopes were requested
103
103
  def openid_scope_requested?
104
- scope = options[:scope] || ""
105
- scope.split(/\s+/).include?("openid")
104
+ scope = options[:scope] || ''
105
+ scope.split(/\s+/).include?('openid')
106
106
  end
107
107
 
108
108
  # Get the appropriate userinfo URL based on environment
109
109
  def userinfo_url
110
- domain = options[:sandbox] ? "sandbox-accounts.platform.intuit.com" : "accounts.platform.intuit.com"
110
+ domain = options[:sandbox] ? 'sandbox-accounts.platform.intuit.com' : 'accounts.platform.intuit.com'
111
111
  "https://#{domain}/v1/openid_connect/userinfo"
112
112
  end
113
113
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omniauth/quickbooks_oauth2_modern/version"
4
- require "omniauth/strategies/quickbooks_oauth2_modern"
3
+ require 'omniauth/quickbooks_oauth2_modern/version'
4
+ require 'omniauth/quickbooks_oauth2_modern/token_client'
5
+ require 'omniauth/strategies/quickbooks_oauth2_modern'
@@ -1,24 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/omniauth/quickbooks_oauth2_modern/version"
3
+ require_relative 'lib/omniauth/quickbooks_oauth2_modern/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "omniauth-quickbooks-oauth2-modern"
6
+ spec.name = 'omniauth-quickbooks-oauth2-modern'
7
7
  spec.version = OmniAuth::QuickbooksOauth2Modern::VERSION
8
- spec.authors = ["dan1d"]
9
- spec.email = ["dan@theowner.me"]
8
+ spec.authors = ['dan1d']
9
+ spec.email = ['dan@theowner.me']
10
10
 
11
- spec.summary = "OmniAuth strategy for QuickBooks Online OAuth 2.0 (OmniAuth 2.0+ compatible)"
12
- spec.description = "An OmniAuth strategy for authenticating with QuickBooks Online using OAuth 2.0. " \
13
- "Compatible with OmniAuth 2.0+ and supports both sandbox and production environments " \
14
- "with OpenID Connect userinfo fetching."
15
- spec.homepage = "https://github.com/dan1d/omniauth-quickbooks-oauth2-modern"
16
- spec.license = "MIT"
17
- spec.required_ruby_version = ">= 3.0.0"
11
+ spec.summary = 'OmniAuth strategy for QuickBooks Online OAuth 2.0 (OmniAuth 2.0+ compatible)'
12
+ spec.description = 'An OmniAuth strategy for authenticating with QuickBooks Online using OAuth 2.0. ' \
13
+ 'Compatible with OmniAuth 2.0+ and supports both sandbox and production environments ' \
14
+ 'with OpenID Connect userinfo fetching.'
15
+ spec.homepage = 'https://github.com/dan1d/omniauth-quickbooks-oauth2-modern'
16
+ spec.license = 'MIT'
17
+ spec.required_ruby_version = '>= 3.0.0'
18
18
 
19
- spec.metadata["homepage_uri"] = spec.homepage
20
- spec.metadata["source_code_uri"] = spec.homepage
21
- spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
19
+ spec.metadata['homepage_uri'] = spec.homepage
20
+ spec.metadata['source_code_uri'] = spec.homepage
21
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
22
+ spec.metadata['rubygems_mfa_required'] = 'true'
22
23
 
23
24
  spec.files = Dir.chdir(__dir__) do
24
25
  `git ls-files -z`.split("\x0").reject do |f|
@@ -26,22 +27,22 @@ Gem::Specification.new do |spec|
26
27
  f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
27
28
  end
28
29
  end
29
- spec.bindir = "exe"
30
+ spec.bindir = 'exe'
30
31
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
- spec.require_paths = ["lib"]
32
+ spec.require_paths = ['lib']
32
33
 
33
34
  # Runtime dependencies
34
- spec.add_dependency "faraday", ">= 1.0", "< 3.0"
35
- spec.add_dependency "omniauth", "~> 2.0"
36
- spec.add_dependency "omniauth-oauth2", "~> 1.8"
35
+ spec.add_dependency 'faraday', '>= 1.0', '< 3.0'
36
+ spec.add_dependency 'omniauth', '~> 2.0'
37
+ spec.add_dependency 'omniauth-oauth2', '~> 1.8'
37
38
 
38
39
  # Development dependencies
39
- spec.add_development_dependency "bundler", "~> 2.0"
40
- spec.add_development_dependency "rack-test", "~> 2.1"
41
- spec.add_development_dependency "rake", "~> 13.0"
42
- spec.add_development_dependency "rspec", "~> 3.12"
43
- spec.add_development_dependency "rubocop", "~> 1.50"
44
- spec.add_development_dependency "rubocop-rspec", "~> 2.20"
45
- spec.add_development_dependency "simplecov", "~> 0.22"
46
- spec.add_development_dependency "webmock", "~> 3.18"
40
+ spec.add_development_dependency 'bundler', '~> 2.0'
41
+ spec.add_development_dependency 'rack-test', '~> 2.1'
42
+ spec.add_development_dependency 'rake', '~> 13.0'
43
+ spec.add_development_dependency 'rspec', '~> 3.12'
44
+ spec.add_development_dependency 'rubocop', '~> 1.50'
45
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.20'
46
+ spec.add_development_dependency 'simplecov', '~> 0.22'
47
+ spec.add_development_dependency 'webmock', '~> 3.18'
47
48
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-quickbooks-oauth2-modern
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dan1d
@@ -185,6 +185,7 @@ files:
185
185
  - README.md
186
186
  - Rakefile
187
187
  - lib/omniauth-quickbooks-oauth2-modern.rb
188
+ - lib/omniauth/quickbooks_oauth2_modern/token_client.rb
188
189
  - lib/omniauth/quickbooks_oauth2_modern/version.rb
189
190
  - lib/omniauth/strategies/quickbooks_oauth2_modern.rb
190
191
  - omniauth-quickbooks-oauth2-modern.gemspec
@@ -195,6 +196,7 @@ metadata:
195
196
  homepage_uri: https://github.com/dan1d/omniauth-quickbooks-oauth2-modern
196
197
  source_code_uri: https://github.com/dan1d/omniauth-quickbooks-oauth2-modern
197
198
  changelog_uri: https://github.com/dan1d/omniauth-quickbooks-oauth2-modern/blob/main/CHANGELOG.md
199
+ rubygems_mfa_required: 'true'
198
200
  rdoc_options: []
199
201
  require_paths:
200
202
  - lib