jwt_auth_client 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +67 -0
- data/LICENSE +21 -0
- data/README.md +168 -79
- data/lib/jwt_auth_client/configuration.rb +142 -26
- data/lib/jwt_auth_client/errors.rb +15 -0
- data/lib/jwt_auth_client/http_client.rb +99 -36
- data/lib/jwt_auth_client/issuable.rb +53 -0
- data/lib/jwt_auth_client/json_decoder.rb +18 -0
- data/lib/jwt_auth_client/token_issuer.rb +50 -38
- data/lib/jwt_auth_client/version.rb +1 -1
- data/lib/jwt_auth_client.rb +8 -13
- metadata +42 -38
- data/Gemfile +0 -27
- data/Gemfile.lock +0 -109
- data/Rakefile +0 -27
- data/lib/jwt_auth_client/billing_client.rb +0 -13
- data/pkg/jwt_auth_client-0.1.0.gem +0 -0
|
@@ -1,63 +1,126 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "faraday"
|
|
4
|
+
require_relative "errors"
|
|
5
|
+
require_relative "json_decoder"
|
|
6
|
+
require_relative "token_issuer"
|
|
2
7
|
|
|
3
8
|
module JwtAuthClient
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
9
|
+
# A thin wrapper around Faraday that issues a JWT for the given user/scopes
|
|
10
|
+
# and injects it as a Bearer token on every outgoing request.
|
|
11
|
+
#
|
|
12
|
+
# The returned connection is safe to keep and reuse for the lifetime of the
|
|
13
|
+
# process: the token is (re)issued lazily per request, so a long-lived
|
|
14
|
+
# connection never sends an expired token.
|
|
7
15
|
class HttpClient
|
|
8
|
-
#
|
|
16
|
+
# Tokens are re-issued when they are this close to expiring, even when
|
|
17
|
+
# token reuse is enabled.
|
|
18
|
+
REFRESH_MARGIN_SECONDS = 30
|
|
19
|
+
|
|
20
|
+
# Builds an authenticated Faraday connection.
|
|
9
21
|
#
|
|
10
|
-
# @param user_id [String]
|
|
11
|
-
# @param target_service [String]
|
|
12
|
-
#
|
|
13
|
-
# @param
|
|
14
|
-
# @
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
# @param user_id [String] the subject the token is issued for. Required.
|
|
23
|
+
# @param target_service [Symbol, String] the audience; must be a key of
|
|
24
|
+
# `configuration.service_urls` unless `base_url` is given. Required.
|
|
25
|
+
# @param scopes [Array<String>] permissions to embed in the token.
|
|
26
|
+
# @param base_url [String, nil] overrides the configured URL for `target_service`
|
|
27
|
+
# (e.g. a canary host). It does not change the `aud` claim.
|
|
28
|
+
# @yieldparam conn [Faraday::Connection] to add middleware (logging,
|
|
29
|
+
# instrumentation, ...) before the adapter is set.
|
|
30
|
+
# @return [Faraday::Connection]
|
|
31
|
+
def self.call(user_id:, target_service:, scopes: [], base_url: nil, &customize)
|
|
32
|
+
new(user_id, target_service, scopes, base_url, &customize).connection
|
|
17
33
|
end
|
|
18
34
|
|
|
19
35
|
attr_reader :user_id, :target_service, :scopes, :base_url
|
|
20
36
|
|
|
21
|
-
|
|
22
|
-
|
|
37
|
+
def initialize(user_id, target_service, scopes, base_url = nil, &customize)
|
|
38
|
+
raise ArgumentError, "user_id is required" if user_id.nil? || user_id.to_s.empty?
|
|
39
|
+
raise ArgumentError, "target_service is required" if target_service.nil? || target_service.to_s.empty?
|
|
40
|
+
|
|
23
41
|
@user_id = user_id
|
|
24
42
|
@target_service = target_service
|
|
25
|
-
@scopes = scopes
|
|
43
|
+
@scopes = Array(scopes)
|
|
26
44
|
@base_url = base_url
|
|
45
|
+
@customize = customize
|
|
27
46
|
@config = JwtAuthClient.configuration
|
|
47
|
+
@token_mutex = Mutex.new
|
|
28
48
|
end
|
|
29
49
|
|
|
30
|
-
#
|
|
31
|
-
# The JWT is issued and included in a request header during this connection setup.
|
|
32
|
-
#
|
|
33
|
-
# @return [Faraday::Connection] The pre-configured Faraday connection.
|
|
50
|
+
# @return [Faraday::Connection] the memoised, pre-configured connection.
|
|
34
51
|
def connection
|
|
35
|
-
@connection ||=
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
@connection ||= begin
|
|
53
|
+
@config.validate!
|
|
54
|
+
Faraday.new(url: determined_base_url) do |conn|
|
|
55
|
+
configure_timeouts(conn)
|
|
56
|
+
|
|
57
|
+
# Evaluated on every request, so the token is always fresh.
|
|
58
|
+
conn.request :authorization, "Bearer", -> { bearer_token }
|
|
59
|
+
conn.request :json
|
|
60
|
+
|
|
61
|
+
# Response middleware runs innermost-first, so declaration order matters:
|
|
62
|
+
# raise_error - outermost: raises on 4xx/5xx once retries are exhausted,
|
|
63
|
+
# with the already-parsed JSON body attached to the error.
|
|
64
|
+
# retry - (opt-in) sees raw statuses, so `retry_statuses` works.
|
|
65
|
+
# json - innermost: parses the body before anything else sees it.
|
|
66
|
+
conn.response :raise_error
|
|
67
|
+
configure_retry(conn)
|
|
68
|
+
conn.response :json, parser_options: { decoder: [JsonDecoder, :parse] }
|
|
69
|
+
|
|
70
|
+
@customize&.call(conn)
|
|
71
|
+
conn.adapter Faraday.default_adapter
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Returns a valid token, issuing a new one when there is none, when the
|
|
77
|
+
# cached one is within REFRESH_MARGIN_SECONDS of expiry, or when
|
|
78
|
+
# `configuration.token_reuse_seconds` has elapsed since it was issued.
|
|
79
|
+
#
|
|
80
|
+
# @return [String]
|
|
81
|
+
def bearer_token
|
|
82
|
+
@token_mutex.synchronize do
|
|
83
|
+
issue_token! if token_stale?
|
|
84
|
+
@token
|
|
44
85
|
end
|
|
45
86
|
end
|
|
46
87
|
|
|
47
88
|
private
|
|
48
89
|
|
|
49
|
-
# Determines the base URL, preferring the local override if provided.
|
|
50
90
|
def determined_base_url
|
|
51
91
|
base_url || @config.base_url_for(target_service)
|
|
52
92
|
end
|
|
53
93
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
94
|
+
def configure_timeouts(conn)
|
|
95
|
+
conn.options.open_timeout = @config.open_timeout
|
|
96
|
+
conn.options.read_timeout = @config.read_timeout
|
|
97
|
+
conn.options.write_timeout = @config.write_timeout
|
|
98
|
+
conn.options.timeout = @config.read_timeout # for adapters that only honour :timeout
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def configure_retry(conn)
|
|
102
|
+
return unless @config.retry_options
|
|
103
|
+
|
|
104
|
+
begin
|
|
105
|
+
require "faraday/retry"
|
|
106
|
+
rescue LoadError
|
|
107
|
+
raise ConfigurationError, "retry_options is set but the faraday-retry gem is not available"
|
|
108
|
+
end
|
|
109
|
+
conn.request :retry, **@config.retry_options
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def token_stale?
|
|
113
|
+
return true if @token.nil?
|
|
114
|
+
|
|
115
|
+
now = Time.now.to_i
|
|
116
|
+
now >= @token_expires_at - REFRESH_MARGIN_SECONDS ||
|
|
117
|
+
now >= @token_issued_at + @config.token_reuse_seconds
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def issue_token!
|
|
121
|
+
@token_issued_at = Time.now.to_i
|
|
122
|
+
@token_expires_at = @token_issued_at + @config.default_expiry_seconds
|
|
123
|
+
@token = TokenIssuer.call(user_id: user_id, target_service: target_service, scopes: scopes)
|
|
61
124
|
end
|
|
62
125
|
end
|
|
63
126
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "token_issuer"
|
|
4
|
+
|
|
5
|
+
module JwtAuthClient
|
|
6
|
+
# Mixin for objects (typically a User model) that can be turned into a JWT,
|
|
7
|
+
# e.g. by an SSO hub handing a signed identity token to a client app.
|
|
8
|
+
#
|
|
9
|
+
# class User < ApplicationRecord
|
|
10
|
+
# include JwtAuthClient::Issuable
|
|
11
|
+
#
|
|
12
|
+
# def jwt_claims
|
|
13
|
+
# { user_id: sso_id, email: email }
|
|
14
|
+
# end
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# user.to_jwt # => "eyJhbGciOi..."
|
|
18
|
+
# user.to_jwt(expiry_seconds: 60)
|
|
19
|
+
#
|
|
20
|
+
# The registered claims (iss, sub, iat, nbf, exp, jti) are always set by the
|
|
21
|
+
# gem; `jwt_claims` cannot override them. `sub` comes from `jwt_subject`,
|
|
22
|
+
# which defaults to `jwt_claims[:user_id]`, falling back to `id`.
|
|
23
|
+
module Issuable
|
|
24
|
+
# Custom claims to embed in the token. Override in the including class.
|
|
25
|
+
#
|
|
26
|
+
# @return [Hash]
|
|
27
|
+
def jwt_claims
|
|
28
|
+
raise NotImplementedError, "#{self.class} must define #jwt_claims returning a Hash of claims"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# The `sub` claim. Override to use a different identifier.
|
|
32
|
+
#
|
|
33
|
+
# @return [String, Integer]
|
|
34
|
+
def jwt_subject
|
|
35
|
+
claims = jwt_claims
|
|
36
|
+
claims[:user_id] || claims["user_id"] || (respond_to?(:id) ? id : nil)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @param expiry_seconds [Integer, nil] overrides the configured default expiry.
|
|
40
|
+
# @param target_service [Symbol, String, nil] optional `aud` claim.
|
|
41
|
+
# @param scopes [Array<String>] optional `scopes` claim.
|
|
42
|
+
# @return [String] the signed JWT.
|
|
43
|
+
def to_jwt(expiry_seconds: nil, target_service: nil, scopes: [])
|
|
44
|
+
TokenIssuer.call(
|
|
45
|
+
user_id: jwt_subject,
|
|
46
|
+
target_service: target_service,
|
|
47
|
+
scopes: scopes,
|
|
48
|
+
claims: jwt_claims,
|
|
49
|
+
expiry_seconds: expiry_seconds
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module JwtAuthClient
|
|
6
|
+
# Adapter handed to Faraday's :json response middleware.
|
|
7
|
+
#
|
|
8
|
+
# Faraday (<= 2.14) calls `decoder.parse(body, options_hash)` with a positional
|
|
9
|
+
# options hash, which `json` >= 3.0 no longer accepts. Forwarding the options as
|
|
10
|
+
# keywords keeps response parsing working on both json 2.x and 3.x.
|
|
11
|
+
module JsonDecoder
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def parse(body, options = {})
|
|
15
|
+
::JSON.parse(body, **options)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -1,60 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "jwt"
|
|
4
|
+
require "securerandom"
|
|
5
|
+
require_relative "errors"
|
|
3
6
|
|
|
4
7
|
module JwtAuthClient
|
|
8
|
+
# Issues short-lived, signed JWTs carrying the registered claims
|
|
9
|
+
# (iss, sub, iat, nbf, exp, jti) plus the optional `aud`, `scopes` and any
|
|
10
|
+
# caller-supplied custom claims.
|
|
5
11
|
class TokenIssuer
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
# Claims that are always set by the issuer and can never be overridden by
|
|
13
|
+
# caller-supplied custom claims.
|
|
14
|
+
REGISTERED_CLAIMS = %i[iss sub iat nbf exp jti].freeze
|
|
15
|
+
|
|
16
|
+
# @param user_id [String] the subject (`sub`) of the token. Required.
|
|
17
|
+
# @param target_service [Symbol, String, nil] the audience (`aud`).
|
|
18
|
+
# @param scopes [Array<String>, nil] permissions granted by the token.
|
|
19
|
+
# @param claims [Hash] extra custom claims (e.g. email); registered claims
|
|
20
|
+
# in this hash are ignored.
|
|
21
|
+
# @param expiry_seconds [Integer, nil] overrides `configuration.default_expiry_seconds`.
|
|
22
|
+
# @return [String] the signed JWT.
|
|
23
|
+
def self.call(user_id:, target_service: nil, scopes: [], claims: {}, expiry_seconds: nil)
|
|
24
|
+
new(user_id, target_service, scopes, claims: claims, expiry_seconds: expiry_seconds).issue
|
|
9
25
|
end
|
|
10
26
|
|
|
11
|
-
|
|
12
|
-
|
|
27
|
+
def initialize(user_id, target_service, scopes, claims: {}, expiry_seconds: nil)
|
|
28
|
+
raise ArgumentError, "user_id is required" if user_id.nil? || user_id.to_s.empty?
|
|
29
|
+
raise ArgumentError, "claims must be a Hash" unless claims.is_a?(Hash)
|
|
30
|
+
unless expiry_seconds.nil? || (expiry_seconds.is_a?(Integer) && expiry_seconds.positive?)
|
|
31
|
+
raise ArgumentError, "expiry_seconds must be a positive Integer"
|
|
32
|
+
end
|
|
33
|
+
|
|
13
34
|
@user_id = user_id
|
|
14
35
|
@target_service = target_service
|
|
15
|
-
@scopes = scopes
|
|
36
|
+
@scopes = Array(scopes)
|
|
37
|
+
@claims = claims
|
|
38
|
+
@expiry_seconds = expiry_seconds
|
|
16
39
|
@config = JwtAuthClient.configuration
|
|
17
40
|
end
|
|
18
41
|
|
|
19
|
-
#
|
|
42
|
+
# @return [String] the signed JWT.
|
|
43
|
+
# @raise [ConfigurationError] if the configuration is invalid.
|
|
44
|
+
# @raise [TokenError] if the jwt gem fails to sign the payload.
|
|
20
45
|
def issue
|
|
21
|
-
|
|
46
|
+
@config.validate!
|
|
47
|
+
JWT.encode(build_payload, @config.shared_secret, @config.algorithm)
|
|
48
|
+
rescue JWT::EncodeError, JWT::DecodeError => e
|
|
49
|
+
# The jwt gem reports bad HMAC keys as DecodeError even on encode.
|
|
50
|
+
raise TokenError, "Failed to sign token: #{e.message}"
|
|
22
51
|
end
|
|
23
52
|
|
|
24
|
-
# --- Private Helper Methods ---
|
|
25
53
|
private
|
|
26
|
-
|
|
27
|
-
def encode
|
|
28
|
-
payload = build_payload
|
|
29
|
-
|
|
30
|
-
# Use the JWT gem to encode the token
|
|
31
|
-
JWT.encode(payload, @config.shared_secret, @config.algorithm)
|
|
32
|
-
end
|
|
33
54
|
|
|
34
|
-
# Uses conditional merging to ensure keys for optional claims (aud, scopes)
|
|
35
|
-
# are only included if they have a non-nil/non-empty value.
|
|
36
55
|
def build_payload
|
|
37
|
-
# Standard JWT Claims (Must include these for security/verification)
|
|
38
56
|
issued_at = Time.now.to_i
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
payload = {
|
|
43
|
-
iss: @config.issuer, # Issuer (e.g., main_sso_app)
|
|
44
|
-
sub: @user_id, # Subject (The user being impersonated)
|
|
45
|
-
iat: issued_at, # Issued At Time
|
|
46
|
-
exp: expiry, # Expiration Time (CRITICAL: short-lived)
|
|
47
|
-
jti: SecureRandom.uuid, # JWT ID (For optional replay attack prevention)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
# 2. Conditionally merge Optional Claims
|
|
51
|
-
# Audience is nil by default
|
|
52
|
-
payload[:aud] = @target_service if @target_service
|
|
53
|
-
|
|
54
|
-
# Scopes are [] by default, so check if the array is not empty
|
|
57
|
+
|
|
58
|
+
payload = @claims.transform_keys(&:to_sym).reject { |key, _| REGISTERED_CLAIMS.include?(key) }
|
|
59
|
+
payload[:aud] = @target_service.to_s unless @target_service.nil? || @target_service.to_s.empty?
|
|
55
60
|
payload[:scopes] = @scopes unless @scopes.empty?
|
|
56
61
|
|
|
57
|
-
payload
|
|
62
|
+
payload.merge!(
|
|
63
|
+
iss: @config.issuer,
|
|
64
|
+
sub: @user_id,
|
|
65
|
+
iat: issued_at,
|
|
66
|
+
nbf: issued_at,
|
|
67
|
+
exp: issued_at + (@expiry_seconds || @config.default_expiry_seconds),
|
|
68
|
+
jti: SecureRandom.uuid
|
|
69
|
+
)
|
|
58
70
|
end
|
|
59
71
|
end
|
|
60
72
|
end
|
data/lib/jwt_auth_client.rb
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
require 'active_support/core_ext/numeric/time' # For N.minutes.from_now logic
|
|
3
|
-
require 'securerandom' # Added for SecureRandom.uuid dependency
|
|
4
|
-
require 'jwt_auth_client/version'
|
|
5
|
-
require 'jwt_auth_client/configuration'
|
|
6
|
-
require 'jwt_auth_client/token_issuer'
|
|
7
|
-
require 'jwt_auth_client/http_client'
|
|
8
|
-
require 'jwt_auth_client/billing_client'
|
|
1
|
+
# frozen_string_literal: true
|
|
9
2
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
require "jwt_auth_client/version"
|
|
4
|
+
require "jwt_auth_client/errors"
|
|
5
|
+
require "jwt_auth_client/configuration"
|
|
6
|
+
require "jwt_auth_client/token_issuer"
|
|
7
|
+
require "jwt_auth_client/issuable"
|
|
8
|
+
require "jwt_auth_client/http_client"
|
|
13
9
|
|
|
14
10
|
module JwtAuthClient
|
|
15
|
-
|
|
16
|
-
end
|
|
11
|
+
end
|
metadata
CHANGED
|
@@ -1,136 +1,140 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jwt_auth_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniele Frisanco
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-09-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: faraday
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '2.
|
|
19
|
+
version: '2.9'
|
|
20
20
|
type: :runtime
|
|
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: '2.
|
|
26
|
+
version: '2.9'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: jwt
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '2.
|
|
33
|
+
version: '2.8'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '2.
|
|
40
|
+
version: '2.8'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: faraday-retry
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
48
|
-
type: :
|
|
47
|
+
version: '2.0'
|
|
48
|
+
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - "
|
|
52
|
+
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
54
|
+
version: '2.0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: rake
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
61
|
+
version: '13.0'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
68
|
+
version: '13.0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
70
|
+
name: rspec
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '
|
|
75
|
+
version: '3.12'
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '
|
|
82
|
+
version: '3.12'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: timecop
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - "~>"
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '
|
|
89
|
+
version: '0.9'
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '
|
|
96
|
+
version: '0.9'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: webmock
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
|
-
- - "
|
|
101
|
+
- - "~>"
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
103
|
+
version: '3.19'
|
|
104
104
|
type: :development
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
|
-
- - "
|
|
108
|
+
- - "~>"
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
111
|
-
description: Generates short-lived, signed JWTs for internal API calls
|
|
112
|
-
|
|
110
|
+
version: '3.19'
|
|
111
|
+
description: Generates short-lived, signed JWTs for internal API calls and injects
|
|
112
|
+
them into Faraday requests as Bearer tokens.
|
|
113
113
|
email:
|
|
114
114
|
- daniele.frisanco@gmail.com
|
|
115
115
|
executables: []
|
|
116
116
|
extensions: []
|
|
117
117
|
extra_rdoc_files: []
|
|
118
118
|
files:
|
|
119
|
-
-
|
|
120
|
-
-
|
|
119
|
+
- CHANGELOG.md
|
|
120
|
+
- LICENSE
|
|
121
121
|
- README.md
|
|
122
|
-
- Rakefile
|
|
123
122
|
- lib/jwt_auth_client.rb
|
|
124
|
-
- lib/jwt_auth_client/billing_client.rb
|
|
125
123
|
- lib/jwt_auth_client/configuration.rb
|
|
124
|
+
- lib/jwt_auth_client/errors.rb
|
|
126
125
|
- lib/jwt_auth_client/http_client.rb
|
|
126
|
+
- lib/jwt_auth_client/issuable.rb
|
|
127
|
+
- lib/jwt_auth_client/json_decoder.rb
|
|
127
128
|
- lib/jwt_auth_client/token_issuer.rb
|
|
128
129
|
- lib/jwt_auth_client/version.rb
|
|
129
|
-
- pkg/jwt_auth_client-0.1.0.gem
|
|
130
130
|
homepage: https://github.com/danielefrisanco/jwt_auth_client
|
|
131
131
|
licenses:
|
|
132
132
|
- MIT
|
|
133
|
-
metadata:
|
|
133
|
+
metadata:
|
|
134
|
+
homepage_uri: https://github.com/danielefrisanco/jwt_auth_client
|
|
135
|
+
source_code_uri: https://github.com/danielefrisanco/jwt_auth_client
|
|
136
|
+
changelog_uri: https://github.com/danielefrisanco/jwt_auth_client/blob/main/CHANGELOG.md
|
|
137
|
+
rubygems_mfa_required: 'true'
|
|
134
138
|
post_install_message:
|
|
135
139
|
rdoc_options: []
|
|
136
140
|
require_paths:
|
|
@@ -139,14 +143,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
139
143
|
requirements:
|
|
140
144
|
- - ">="
|
|
141
145
|
- !ruby/object:Gem::Version
|
|
142
|
-
version: '
|
|
146
|
+
version: '3.1'
|
|
143
147
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
148
|
requirements:
|
|
145
149
|
- - ">="
|
|
146
150
|
- !ruby/object:Gem::Version
|
|
147
151
|
version: '0'
|
|
148
152
|
requirements: []
|
|
149
|
-
rubygems_version: 3.
|
|
153
|
+
rubygems_version: 3.3.26
|
|
150
154
|
signing_key:
|
|
151
155
|
specification_version: 4
|
|
152
156
|
summary: Secure client for generating and sending internal service-to-service JWTs.
|
data/Gemfile
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
source "https://rubygems.org"
|
|
2
|
-
gemspec
|
|
3
|
-
group :development, :test do
|
|
4
|
-
gem 'pry', '~> 0.14'
|
|
5
|
-
|
|
6
|
-
# Core HTTP Client
|
|
7
|
-
gem 'faraday', '~> 2.7'
|
|
8
|
-
|
|
9
|
-
# For conn.request :retry (now typically part of the faraday-excon or faraday-net_http gems)
|
|
10
|
-
# gem 'faraday-retry' # You might need this explicitly if on an older version of Faraday 2+
|
|
11
|
-
|
|
12
|
-
gem 'webmock', '~> 3.19' # For HTTP stubbing/testing
|
|
13
|
-
gem 'timecop', '~> 0.9' # For time-based testing
|
|
14
|
-
# Testing tools
|
|
15
|
-
gem 'rspec', '~> 3.0'
|
|
16
|
-
|
|
17
|
-
# Faraday and required middleware
|
|
18
|
-
# The core faraday gem is already included via gemspec
|
|
19
|
-
# We must explicitly add the middleware that replaced faraday-middleware and faraday-json
|
|
20
|
-
gem 'faraday-typhoeus' # A robust adapter
|
|
21
|
-
gem 'faraday-retry', '~> 2.0' # Explicit gem for the :retry middleware
|
|
22
|
-
|
|
23
|
-
# Note: JSON encoding/decoding middleware is often implicitly handled
|
|
24
|
-
# by faraday v2, or included in faraday-typhoeus or a different gem
|
|
25
|
-
# depending on the setup. Explicitly adding :json requests/responses
|
|
26
|
-
# in the HttpClient often just needs the `json` gem itself.
|
|
27
|
-
end
|