boldsign 0.4.0 → 0.6.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: cbe0865fb65380ebdee0b2a2ccca3804a3cac90639d93778cc7350ca202294d4
4
- data.tar.gz: 93dc1c1e373d29ea4bf07af0622da0662fd5d6d0b044e317ce6e69ceb442743b
3
+ metadata.gz: 1f5158801c4b85358c9f7b45376a2767bb98c3374e994b2cb643840245ce641f
4
+ data.tar.gz: d4748c0000aabf9012b0d0403ca54d147a5bf190674cf80c96079302fa97dd95
5
5
  SHA512:
6
- metadata.gz: 27eb15a5d89fe793cbae44f5e67ebb6b1c52eb71313e2ef677e57b004384f40e552dcebd53525c86c7ddb14d30f3fb278fe9e955aeadb39b5a2d573eb309704a
7
- data.tar.gz: 6d11a55a16fb6f553e5136dde756baa972ebed48e0b6a5ebeac50cc3abf27b3d0ca2d2bc47103fe42ea2c3933c3a4a2c9f2d8704ed7ebd546d60c7cee69ca953
6
+ metadata.gz: 7b8e468b7897ee9a34c9bed4256cd2fd305a58e43af9ab07c889de9ad5c024d8da6e7b01b4bc1d3ca572e5b785b786ebc9544b4559797b7e95d96cc01cb493ea
7
+ data.tar.gz: 29670ea3951d2adade1a687d6786510409e48707d27844dedc07b2659637b3ea7c5089672ea1f9d550e7fced26d89fcd2f98c4bea29ae324430e83652d807550
data/CHANGELOG.md CHANGED
@@ -7,6 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.0] — 2026-07-27
11
+
12
+ ### Added
13
+ - Multi-signer support for multipart `send_document` (file uploads). Array-valued
14
+ body fields (e.g. `signers: [...]`) now emit one JSON-object part per element,
15
+ all under the same field name (`Signers`, `Signers`, …) via
16
+ `Faraday::Multipart::Middleware`'s `flat_encode: true` — confirmed against
17
+ BoldSign's docs as the correct encoding for a multi-recipient envelope sent
18
+ alongside an uploaded file (as opposed to a template reference). Previously
19
+ this raised `NotImplementedError`. Multi-file uploads are still unsupported
20
+ and still raise.
21
+
22
+ ## [0.5.0] — 2026-06-02
23
+
24
+ ### Added
25
+ - OAuth 2.0 authentication via the **client credentials** grant. Configure
26
+ `client_id` / `client_secret` (on `Boldsign.configure` or `Client.new`) and
27
+ the client fetches a bearer token from the region's account host
28
+ (`https://account.boldsign.com/connect/token` for `:us`), caches it until
29
+ shortly before `expires_in` lapses, and sends `Authorization: Bearer …`
30
+ instead of `X-API-KEY`. Token fetches are mutex-guarded for shared clients.
31
+ - `scope:` (defaults to `BoldSign.Documents.All`) and `token_url:` options to
32
+ override the requested scope and token endpoint.
33
+ - `access_token:` option to supply a pre-obtained bearer token that is used
34
+ as-is (not refreshed).
35
+ - `Boldsign::AccessToken` encapsulating the client-credentials token lifecycle.
36
+ - `TOKEN_REGIONS` / `DEFAULT_TOKEN_BASE_URL` constants and `Client#auth_mode`.
37
+
38
+ ### Changed
39
+ - `Client.new` no longer requires an API key. It accepts any one of
40
+ `client_id`/`client_secret`, `access_token`, or `api_key`, and raises
41
+ `ConfigurationError` only when none is provided. The API-key path is
42
+ unchanged, so existing `api_key:` callers keep working.
43
+
10
44
  ## [0.4.0] — 2026-05-22
11
45
 
12
46
  ### Changed
@@ -68,5 +102,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
68
102
  - 100% line and branch test coverage enforced via SimpleCov.
69
103
  - GitHub Actions CI on Ruby 3.4 and 4.0.
70
104
 
71
- [Unreleased]: https://github.com/kleinjm/boldsign-ruby/compare/v0.1.0...HEAD
72
- [0.1.0]: https://github.com/kleinjm/boldsign-ruby/releases/tag/v0.1.0
105
+ [Unreleased]: https://github.com/EscrowSafe/boldsign-ruby/compare/v0.6.0...HEAD
106
+ [0.6.0]: https://github.com/EscrowSafe/boldsign-ruby/compare/v0.5.0...v0.6.0
107
+ [0.5.0]: https://github.com/EscrowSafe/boldsign-ruby/compare/v0.4.0...v0.5.0
108
+ [0.1.0]: https://github.com/EscrowSafe/boldsign-ruby/releases/tag/v0.1.0
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # boldsign-ruby
2
2
 
3
- [![CI](https://github.com/kleinjm/boldsign-ruby/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/kleinjm/boldsign-ruby/actions/workflows/ci.yml)
4
- [![API docs](https://img.shields.io/badge/docs-rubydoc.info-blue.svg)](https://rubydoc.info/github/kleinjm/boldsign-ruby/main)
3
+ [![CI](https://github.com/EscrowSafe/boldsign-ruby/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/EscrowSafe/boldsign-ruby/actions/workflows/ci.yml)
4
+ [![API docs](https://img.shields.io/badge/docs-rubydoc.info-blue.svg)](https://rubydoc.info/github/EscrowSafe/boldsign-ruby/main)
5
5
 
6
6
  A Ruby client for the [BoldSign](https://developers.boldsign.com/) e-signature API.
7
7
 
@@ -17,6 +17,32 @@ gem "boldsign"
17
17
 
18
18
  ## Configuration
19
19
 
20
+ The client authenticates with either an API key or OAuth 2.0.
21
+
22
+ ### OAuth 2.0 (client credentials)
23
+
24
+ Register an OAuth app in the BoldSign dashboard (API → OAuth Apps) and configure
25
+ its `client_id` / `client_secret`. The client fetches a bearer token from the
26
+ region's account host, caches it until shortly before it expires, and refreshes
27
+ automatically — no token plumbing on your side.
28
+
29
+ ```ruby
30
+ Boldsign.configure do |c|
31
+ c.client_id = ENV["BOLDSIGN_CLIENT_ID"]
32
+ c.client_secret = ENV["BOLDSIGN_CLIENT_SECRET"]
33
+ c.region = :us # :us, :eu, :ca, :au
34
+ # c.scope = "BoldSign.Documents.All" # optional; empty grants all the app allows
35
+ end
36
+ ```
37
+
38
+ You can also pass a token you obtained yourself (used as-is, not refreshed):
39
+
40
+ ```ruby
41
+ Boldsign::Client.new(access_token: "…", region: :us)
42
+ ```
43
+
44
+ ### API key
45
+
20
46
  ```ruby
21
47
  Boldsign.configure do |c|
22
48
  c.api_key = ENV["BOLDSIGN_API_KEY"]
@@ -30,14 +56,17 @@ Or instantiate a client directly:
30
56
  client = Boldsign::Client.new(api_key: "…", region: :us)
31
57
  ```
32
58
 
33
- Region base URLs:
59
+ Region hosts:
60
+
61
+ | Region | API base URL | OAuth account host |
62
+ | ------ | ------------ | ------------------ |
63
+ | `:us` | `https://api.boldsign.com` | `https://account.boldsign.com` |
64
+ | `:eu` | `https://api-eu.boldsign.com` | `https://account-eu.boldsign.com` |
65
+ | `:ca` | `https://api-ca.boldsign.com` | `https://account-ca.boldsign.com` |
66
+ | `:au` | `https://api-au.boldsign.com` | `https://account-au.boldsign.com` |
34
67
 
35
- | Region | URL |
36
- | ------ | --- |
37
- | `:us` | `https://api.boldsign.com` |
38
- | `:eu` | `https://api-eu.boldsign.com` |
39
- | `:ca` | `https://api-ca.boldsign.com` |
40
- | `:au` | `https://api-au.boldsign.com` |
68
+ The token endpoint is the account host + `/connect/token`; override the full URL
69
+ with `token_url:` if a region differs.
41
70
 
42
71
  ## Usage
43
72
 
@@ -109,7 +138,7 @@ HTTP errors raise a typed subclass of `Boldsign::Error`:
109
138
  ## Documentation
110
139
 
111
140
  Full YARD API documentation is auto-built and hosted at
112
- [rubydoc.info/github/kleinjm/boldsign-ruby/main](https://rubydoc.info/github/kleinjm/boldsign-ruby/main).
141
+ [rubydoc.info/github/EscrowSafe/boldsign-ruby/main](https://rubydoc.info/github/EscrowSafe/boldsign-ruby/main).
113
142
 
114
143
  To generate locally:
115
144
 
data/boldsign.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.summary = "Ruby client for the BoldSign e-signature API"
10
10
  spec.description = "A Ruby wrapper for the BoldSign REST API (documents, templates, " \
11
11
  "contacts, teams, brands, webhooks, and more)."
12
- spec.homepage = "https://github.com/kleinjm/boldsign-ruby"
12
+ spec.homepage = "https://github.com/EscrowSafe/boldsign-ruby"
13
13
  spec.license = "MIT"
14
14
  spec.required_ruby_version = ">= 3.0"
15
15
 
@@ -0,0 +1,95 @@
1
+ module Boldsign
2
+ # Fetches and caches an OAuth 2.0 access token using the client credentials
3
+ # grant (server-to-server; no user interaction).
4
+ #
5
+ # A single instance is shared by a {Client} and may be hit from multiple
6
+ # threads, so token reads/refreshes are guarded by a mutex. The token is
7
+ # cached until shortly before it expires ({EXPIRY_LEEWAY_SECONDS}), then a new
8
+ # one is requested on the next call. The client credentials grant does not
9
+ # issue refresh tokens — expiry is handled by re-requesting.
10
+ #
11
+ # @see https://developers.boldsign.com/authentication/oauth-2-0/
12
+ class AccessToken
13
+ # Token endpoint path, appended to the region's account host.
14
+ TOKEN_PATH = "/connect/token".freeze
15
+
16
+ # Default scope requested for the access token. Covers the document /
17
+ # signature endpoints this gem is primarily used for. Pass a different
18
+ # `scope:` to request others (an empty scope grants all the app is allowed).
19
+ DEFAULT_SCOPE = "BoldSign.Documents.All".freeze
20
+
21
+ # Refresh this many seconds before the token actually expires, so an
22
+ # in-flight request never carries a token that lapses server-side mid-call.
23
+ EXPIRY_LEEWAY_SECONDS = 60
24
+
25
+ # Fallback lifetime (seconds) when the token response omits `expires_in`.
26
+ DEFAULT_EXPIRES_IN = 3600
27
+
28
+ # @param client_id [String] OAuth app client ID.
29
+ # @param client_secret [String] OAuth app client secret.
30
+ # @param token_url [String] Full token endpoint URL (host + {TOKEN_PATH}).
31
+ # @param scope [String] OAuth scope to request.
32
+ # @param adapter [Symbol] Faraday adapter.
33
+ def initialize(client_id:, client_secret:, token_url:, scope: DEFAULT_SCOPE,
34
+ adapter: Faraday.default_adapter)
35
+ @client_id = client_id
36
+ @client_secret = client_secret
37
+ @token_url = token_url
38
+ @scope = scope
39
+ @adapter = adapter
40
+ @mutex = Mutex.new
41
+ end
42
+
43
+ # @return [String] a currently-valid bearer token, fetching or refreshing
44
+ # one if the cached token is missing or near expiry.
45
+ def value
46
+ @mutex.synchronize do
47
+ refresh! if expired?
48
+ @token
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def expired?
55
+ @token.nil? || Time.now >= @expires_at
56
+ end
57
+
58
+ def refresh!
59
+ response = connection.post(@token_url) do |req|
60
+ req.headers["Content-Type"] = "application/x-www-form-urlencoded"
61
+ req.body = URI.encode_www_form(
62
+ grant_type: "client_credentials",
63
+ client_id: @client_id,
64
+ client_secret: @client_secret,
65
+ scope: @scope
66
+ )
67
+ end
68
+ raise_token_error(response) unless response.success?
69
+
70
+ body = JSON.parse(response.body)
71
+ @token = body["access_token"]
72
+ expires_in = (body["expires_in"] || DEFAULT_EXPIRES_IN).to_i
73
+ @expires_at = Time.now + expires_in - EXPIRY_LEEWAY_SECONDS
74
+ end
75
+
76
+ def connection
77
+ Faraday.new do |f|
78
+ f.adapter @adapter
79
+ end
80
+ end
81
+
82
+ def raise_token_error(response)
83
+ body = begin
84
+ JSON.parse(response.body)
85
+ rescue StandardError
86
+ response.body
87
+ end
88
+ message = body.is_a?(Hash) ? (body["error_description"] || body["error"] || body.to_s) : body.to_s
89
+ raise AuthenticationError.new(
90
+ "BoldSign OAuth token request failed (#{response.status}): #{message}",
91
+ status: response.status, body: body, response: response
92
+ )
93
+ end
94
+ end
95
+ end
@@ -8,9 +8,21 @@ module Boldsign
8
8
  # Low-level verb methods ({#get}, {#post}, {#put}, {#patch}, {#delete},
9
9
  # {#download}) are also available for hitting any endpoint directly.
10
10
  #
11
- # @example
11
+ # Authenticates with either an API key (`X-API-KEY`) or OAuth 2.0
12
+ # (`Authorization: Bearer`). For OAuth, pass `client_id`/`client_secret` and
13
+ # the client fetches + caches a token via the client credentials grant; or
14
+ # pass a `access_token` you obtained yourself.
15
+ #
16
+ # @example API key
12
17
  # client = Boldsign::Client.new(api_key: ENV["BOLDSIGN_API_KEY"], region: :us)
13
18
  # client.documents.send_document(title: "NDA", signers: [...])
19
+ #
20
+ # @example OAuth client credentials
21
+ # client = Boldsign::Client.new(
22
+ # client_id: ENV["BOLDSIGN_CLIENT_ID"],
23
+ # client_secret: ENV["BOLDSIGN_CLIENT_SECRET"],
24
+ # region: :us
25
+ # )
14
26
  class Client
15
27
  # Default region (US).
16
28
  DEFAULT_BASE_URL = "https://api.boldsign.com".freeze
@@ -18,25 +30,50 @@ module Boldsign
18
30
  # User-Agent header value sent on every request.
19
31
  USER_AGENT = "boldsign-ruby/#{Boldsign::VERSION}".freeze
20
32
 
21
- # @return [String] the API key in use.
33
+ # @return [String, nil] the API key in use, when authenticating via API key.
22
34
  attr_reader :api_key
23
35
 
36
+ # @return [Symbol] the resolved auth mode (`:api_key`, `:oauth`, or `:bearer`).
37
+ attr_reader :auth_mode
38
+
24
39
  # @return [String] the resolved base URL (region or explicit override).
25
40
  attr_reader :base_url
26
41
 
27
42
  # @param api_key [String, nil] BoldSign API key. Falls back to `ENV["BOLDSIGN_API_KEY"]`.
28
- # @param region [Symbol, nil] One of `:us`, `:eu`, `:ca`, `:au`. Ignored if `base_url` is given.
29
- # @param base_url [String, nil] Explicit base URL override.
43
+ # @param client_id [String, nil] OAuth app client ID (enables the client credentials grant).
44
+ # @param client_secret [String, nil] OAuth app client secret (required with `client_id`).
45
+ # @param access_token [String, nil] A pre-obtained OAuth bearer token (used as-is, not refreshed).
46
+ # @param scope [String, nil] OAuth scope to request (defaults to {AccessToken::DEFAULT_SCOPE}).
47
+ # @param token_url [String, nil] Override for the full OAuth token endpoint URL.
48
+ # @param region [Symbol, nil] One of `:us`, `:eu`, `:ca`, `:au`. Ignored if `base_url`/`token_url` is given.
49
+ # @param base_url [String, nil] Explicit API base URL override.
30
50
  # @param adapter [Symbol] Faraday adapter (defaults to `Faraday.default_adapter`).
31
51
  # @param logger [Logger, nil] Optional logger; when present, Faraday's logger middleware is enabled.
32
- # @raise [ConfigurationError] when no API key is available.
33
- def initialize(api_key: nil, region: nil, base_url: nil, adapter: Faraday.default_adapter, logger: nil)
52
+ # @raise [ConfigurationError] when no usable credentials are provided.
53
+ def initialize(api_key: nil, client_id: nil, client_secret: nil, access_token: nil,
54
+ scope: nil, token_url: nil, region: nil, base_url: nil,
55
+ adapter: Faraday.default_adapter, logger: nil)
34
56
  @api_key = api_key || ENV["BOLDSIGN_API_KEY"]
35
- raise ConfigurationError, "Missing BoldSign API key" if @api_key.nil? || @api_key.empty?
36
-
57
+ @static_access_token = access_token
37
58
  @base_url = base_url || Boldsign::REGIONS[region&.to_sym] || DEFAULT_BASE_URL
38
59
  @adapter = adapter
39
60
  @logger = logger
61
+
62
+ if present?(client_id) && present?(client_secret)
63
+ @auth_mode = :oauth
64
+ @access_token = AccessToken.new(
65
+ client_id: client_id, client_secret: client_secret,
66
+ token_url: token_url || default_token_url(region),
67
+ scope: scope || AccessToken::DEFAULT_SCOPE, adapter: adapter
68
+ )
69
+ elsif present?(@static_access_token)
70
+ @auth_mode = :bearer
71
+ elsif present?(@api_key)
72
+ @auth_mode = :api_key
73
+ else
74
+ raise ConfigurationError,
75
+ "Missing BoldSign credentials: provide client_id/client_secret, access_token, or api_key"
76
+ end
40
77
  end
41
78
 
42
79
  # @return [Resources::Brand]
@@ -135,9 +172,15 @@ module Boldsign
135
172
 
136
173
  def connection(multipart: false)
137
174
  Faraday.new(url: @base_url) do |f|
138
- f.request :multipart if multipart
175
+ # flat_encode: true makes Faraday::Multipart::Middleware emit each
176
+ # Array element as its own part under the *same* field name (e.g. two
177
+ # `Signers` parts) instead of bracket-suffixing it (`Signers[]=`),
178
+ # which BoldSign's /v1/document/send endpoint rejects. See
179
+ # Resources::Document#encode_multipart_value, the caller that relies
180
+ # on this.
181
+ f.request :multipart, flat_encode: true if multipart
139
182
  f.request :url_encoded
140
- f.headers["X-API-KEY"] = @api_key
183
+ apply_auth(f.headers)
141
184
  f.headers["Accept"] = "application/json"
142
185
  f.headers["User-Agent"] = USER_AGENT
143
186
  f.response :logger, @logger if @logger
@@ -145,6 +188,27 @@ module Boldsign
145
188
  end
146
189
  end
147
190
 
191
+ def apply_auth(headers)
192
+ if @auth_mode == :api_key
193
+ headers["X-API-KEY"] = @api_key
194
+ else
195
+ headers["Authorization"] = "Bearer #{bearer_token}"
196
+ end
197
+ end
198
+
199
+ def bearer_token
200
+ @auth_mode == :oauth ? @access_token.value : @static_access_token
201
+ end
202
+
203
+ def present?(value)
204
+ !value.nil? && !value.empty?
205
+ end
206
+
207
+ def default_token_url(region)
208
+ base = Boldsign::TOKEN_REGIONS[region&.to_sym] || Boldsign::DEFAULT_TOKEN_BASE_URL
209
+ "#{base}#{AccessToken::TOKEN_PATH}"
210
+ end
211
+
148
212
  def parse_body(response)
149
213
  return nil if response.body.nil? || response.body.empty?
150
214
  content_type = response.headers["content-type"].to_s
@@ -74,13 +74,16 @@ module Boldsign
74
74
  private
75
75
 
76
76
  # BoldSign's POST /v1/document/send multipart endpoint is fussy about
77
- # repeated/array-valued parts. Single signers must be sent as one
78
- # multipart part whose value is the signer JSON OBJECT (not a JSON array
79
- # containing one object). Files must be sent as a single FilePart value
80
- # for one upload; Faraday's automatic `Files[]` bracketing breaks the
81
- # request. For the single-signer, single-file flow (the common case) we
82
- # unwrap one-element arrays here. Multi-signer / multi-file is not yet
83
- # supported via this helper and will raise.
77
+ # repeated/array-valued parts. Multi-valued fields (e.g. two signers)
78
+ # must be sent as one multipart part per element, each keyed with the
79
+ # *same* field name and JSON-encoding just that one element not a
80
+ # single field whose value is a JSON array, and not Faraday's default
81
+ # `Signers[]=` bracket-suffixed encoding (BoldSign rejects both). See
82
+ # `Client#connection`'s `flat_encode: true`, which is what makes
83
+ # `encode_multipart_value`'s Array output emit that way. Files must be
84
+ # sent as a single FilePart value for one upload; Faraday's automatic
85
+ # `Files[]` bracketing breaks the request the same way. Multi-file is
86
+ # not yet supported via this helper and will raise.
84
87
  def multipart_send_body(body, files)
85
88
  parts = body.each_with_object({}) do |(key, value), acc|
86
89
  next if value.nil?
@@ -95,12 +98,15 @@ module Boldsign
95
98
  parts
96
99
  end
97
100
 
101
+ # Scalars pass through as-is. A Hash (or single-element Array, once
102
+ # `flat_encode` unwraps it to one part) becomes one JSON-object part.
103
+ # A multi-element Array becomes one JSON-object part *per element*,
104
+ # all sharing the same field name — see `multipart_send_body`'s comment.
98
105
  def encode_multipart_value(value)
99
106
  return value.to_s if scalar?(value)
100
- return JSON.generate(Boldsign::CaseConvert.camelize(value)) unless value.is_a?(Array)
101
- raise NotImplementedError, "multi-element arrays are not supported in multipart bodies yet" if value.size > 1
107
+ return value.map { |v| JSON.generate(Boldsign::CaseConvert.camelize(v)) } if value.is_a?(Array)
102
108
 
103
- JSON.generate(Boldsign::CaseConvert.camelize(value.first))
109
+ JSON.generate(Boldsign::CaseConvert.camelize(value))
104
110
  end
105
111
 
106
112
  def file_part(file)
@@ -1,3 +1,3 @@
1
1
  module Boldsign
2
- VERSION = "0.4.0"
2
+ VERSION = "0.6.0"
3
3
  end
data/lib/boldsign.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  require "faraday"
2
2
  require "faraday/multipart"
3
3
  require "json"
4
+ require "uri"
4
5
 
5
6
  require_relative "boldsign/version"
6
7
  require_relative "boldsign/error"
7
8
  require_relative "boldsign/case_convert"
9
+ require_relative "boldsign/access_token"
8
10
  require_relative "boldsign/client"
9
11
  require_relative "boldsign/resource"
10
12
  require_relative "boldsign/resources/brand"
@@ -24,10 +26,11 @@ require_relative "boldsign/resources/user"
24
26
  # Configure once at boot and access a shared {Client} via {Boldsign.client}, or
25
27
  # instantiate {Client} directly when you need multiple credentials/regions.
26
28
  #
27
- # @example Configure and use the shared client
29
+ # @example Configure with OAuth and use the shared client
28
30
  # Boldsign.configure do |c|
29
- # c.api_key = ENV["BOLDSIGN_API_KEY"]
30
- # c.region = :us
31
+ # c.client_id = ENV["BOLDSIGN_CLIENT_ID"]
32
+ # c.client_secret = ENV["BOLDSIGN_CLIENT_SECRET"]
33
+ # c.region = :us
31
34
  # end
32
35
  # Boldsign.client.documents.list
33
36
  module Boldsign
@@ -39,10 +42,37 @@ module Boldsign
39
42
  au: "https://api-au.boldsign.com"
40
43
  }.freeze
41
44
 
45
+ # Region → account host map for the OAuth token endpoint. Non-US hosts follow
46
+ # BoldSign's regional naming; override with `token_url:` if a region differs.
47
+ TOKEN_REGIONS = {
48
+ us: "https://account.boldsign.com",
49
+ eu: "https://account-eu.boldsign.com",
50
+ ca: "https://account-ca.boldsign.com",
51
+ au: "https://account-au.boldsign.com"
52
+ }.freeze
53
+
54
+ # Default account host (US) for the OAuth token endpoint.
55
+ DEFAULT_TOKEN_BASE_URL = "https://account.boldsign.com".freeze
56
+
42
57
  class << self
43
58
  # @return [String, nil] API key used by the shared {client}.
44
59
  attr_accessor :api_key
45
60
 
61
+ # @return [String, nil] OAuth app client ID used by the shared {client}.
62
+ attr_accessor :client_id
63
+
64
+ # @return [String, nil] OAuth app client secret used by the shared {client}.
65
+ attr_accessor :client_secret
66
+
67
+ # @return [String, nil] Pre-obtained OAuth bearer token (used as-is, not refreshed).
68
+ attr_accessor :access_token
69
+
70
+ # @return [String, nil] OAuth scope to request (defaults to {AccessToken::DEFAULT_SCOPE}).
71
+ attr_accessor :scope
72
+
73
+ # @return [String, nil] Override for the full OAuth token endpoint URL.
74
+ attr_accessor :token_url
75
+
46
76
  # @return [Symbol, nil] Region key (`:us`, `:eu`, `:ca`, `:au`).
47
77
  attr_accessor :region
48
78
 
@@ -58,7 +88,11 @@ module Boldsign
58
88
 
59
89
  # @return [Client] memoized shared client built from module-level config.
60
90
  def client
61
- @client ||= Client.new(api_key: api_key, region: region, base_url: base_url)
91
+ @client ||= Client.new(
92
+ api_key: api_key, client_id: client_id, client_secret: client_secret,
93
+ access_token: access_token, scope: scope, token_url: token_url,
94
+ region: region, base_url: base_url
95
+ )
62
96
  end
63
97
 
64
98
  # Clears the memoized shared client so the next call to {client} rebuilds it.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boldsign
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Klein
@@ -92,6 +92,7 @@ files:
92
92
  - README.md
93
93
  - boldsign.gemspec
94
94
  - lib/boldsign.rb
95
+ - lib/boldsign/access_token.rb
95
96
  - lib/boldsign/case_convert.rb
96
97
  - lib/boldsign/client.rb
97
98
  - lib/boldsign/error.rb
@@ -108,14 +109,14 @@ files:
108
109
  - lib/boldsign/resources/template.rb
109
110
  - lib/boldsign/resources/user.rb
110
111
  - lib/boldsign/version.rb
111
- homepage: https://github.com/kleinjm/boldsign-ruby
112
+ homepage: https://github.com/EscrowSafe/boldsign-ruby
112
113
  licenses:
113
114
  - MIT
114
115
  metadata:
115
- homepage_uri: https://github.com/kleinjm/boldsign-ruby
116
- source_code_uri: https://github.com/kleinjm/boldsign-ruby
117
- changelog_uri: https://github.com/kleinjm/boldsign-ruby/blob/main/CHANGELOG.md
118
- bug_tracker_uri: https://github.com/kleinjm/boldsign-ruby/issues
116
+ homepage_uri: https://github.com/EscrowSafe/boldsign-ruby
117
+ source_code_uri: https://github.com/EscrowSafe/boldsign-ruby
118
+ changelog_uri: https://github.com/EscrowSafe/boldsign-ruby/blob/main/CHANGELOG.md
119
+ bug_tracker_uri: https://github.com/EscrowSafe/boldsign-ruby/issues
119
120
  documentation_uri: https://rubydoc.info/gems/boldsign
120
121
  rubygems_mfa_required: 'true'
121
122
  rdoc_options: []