jwt_signed_request 1.2.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6fa8c63dbbcbd416f397ff940a5456134d94e764
4
- data.tar.gz: 794b7c510557b12ed9947eba5e1c82b79c944ff1
3
+ metadata.gz: 6fb3525b6977202315ff48f351757ed3e9c6c010
4
+ data.tar.gz: 3e7f295a2d568f8350d67354f03433f4869b72e8
5
5
  SHA512:
6
- metadata.gz: fe0c6c4b1149b267fae6a00818fd818e8731e1d9bcac00b495abe6751d70f5f7e7ae88ed857fea012c05a3a29132ff2e148b488d6ecab566d4d3f523d63d702c
7
- data.tar.gz: 9951441f024bf82334b30099a6ee4d586c6f49a550c1bc32a3c9cc261eebd9d49b4f68c635663e8c3f0679f580fd4a11e680518591b6377f16590c9607b55309
6
+ metadata.gz: 537683653302ef5695e2ec9cf78ad2e368aff14db1bdf854ed16aa0ed82a5902457e980d0594b297f591fe1837da9aee7871ed4c8c10bb7099a52e1f0eadcab5
7
+ data.tar.gz: e29633992973869ceb8f8857f8b7bef580f5bf632c8b80e26a141c9501eb8e51625916d250481580f26ce22d4a5c429f9693e924825d46b2687852bf148ee99b
data/README.md CHANGED
@@ -28,9 +28,46 @@ $ openssl ec -in myprivatekey.pem -pubout -out mypubkey.pem
28
28
 
29
29
  Store and encrypt these in your application secrets.
30
30
 
31
+ ## Configuration
32
+
33
+ You can add signing and verification keys to the key store as your application needs them.
34
+
35
+ ```ruby
36
+ private_key = <<-pem.gsub(/^\s+/, "")
37
+ -----BEGIN EC PRIVATE KEY-----
38
+ MHcCAQEEIBOQ3YIILYMV1glTKbF9oeZWzHe3SNQjAx4IbPIxNygQoAoGCCqGSM49
39
+ AwEHoUQDQgAEuOC3ufTTnW0hVmCPNERb4LxaDE/OexDdlmXEjHYaixzYIduluGXd
40
+ 3cjg4H2gjqsY/NCpJ9nM8/AAINSrq+qPuA==
41
+ -----END EC PRIVATE KEY-----
42
+ pem
43
+
44
+ public_key = <<-pem.gsub(/^\s+/, "")
45
+ -----BEGIN PUBLIC KEY-----
46
+ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuOC3ufTTnW0hVmCPNERb4LxaDE/O
47
+ exDdlmXEjHYaixzYIduluGXd3cjg4H2gjqsY/NCpJ9nM8/AAINSrq+qPuA==
48
+ -----END PUBLIC KEY-----
49
+ pem
50
+
51
+ require 'openssl'
52
+
53
+ JWTSignedRequest.configure_keys do |config|
54
+ config.add_signing_key(
55
+ key_id: 'client_a',
56
+ key: OpenSSL::PKey::EC.new(private_key),
57
+ algorithm: 'ES256',
58
+ )
59
+
60
+ config.add_verification_key(
61
+ key_id: 'client_a',
62
+ key: OpenSSL::PKey::EC.new(public_key),
63
+ algorithm: 'ES256',
64
+ )
65
+ end
66
+ ```
67
+
31
68
  ## Signing Requests
32
69
 
33
- If you are using an asymmetrical encryption algorithm such as ES256 you will sign your requests using the private key.
70
+ If you have added your signing keys to the key store, you will only need to specify the `key_id` you are signing the requests with.
34
71
 
35
72
  ### Using net/http
36
73
 
@@ -40,14 +77,6 @@ require 'uri'
40
77
  require 'openssl'
41
78
  require 'jwt_signed_request'
42
79
 
43
- private_key = """
44
- -----BEGIN EC PRIVATE KEY-----
45
- MHcCAQEEIBOQ3YIILYMV1glTKbF9oeZWzHe3SNQjAx4IbPIxNygQoAoGCCqGSM49
46
- AwEHoUQDQgAEuOC3ufTTnW0hVmCPNERb4LxaDE/OexDdlmXEjHYaixzYIduluGXd
47
- 3cjg4H2gjqsY/NCpJ9nM8/AAINSrq+qPuA==
48
- -----END EC PRIVATE KEY-----
49
- """
50
-
51
80
  uri = URI('http://example.com')
52
81
  req = Net::HTTP::Get.new(uri)
53
82
 
@@ -56,9 +85,7 @@ req['Authorization'] = JWTSignedRequest.sign(
56
85
  path: req.path,
57
86
  headers: {"Content-Type" => "application/json"},
58
87
  body: "",
59
- secret_key: OpenSSL::PKey::EC.new(private_key),
60
- algorithm: 'ES256', # optional (default: ES256)
61
- key_id: 'my-key-id', # optional
88
+ key_id: 'my-key-id',
62
89
  issuer: 'my-issuer' # optional
63
90
  additional_headers_to_sign: ['X-AUTH'] # optional
64
91
  )
@@ -75,19 +102,9 @@ require 'faraday'
75
102
  require 'openssl'
76
103
  require 'jwt_signed_request/middlewares/faraday'
77
104
 
78
- private_key = """
79
- -----BEGIN EC PRIVATE KEY-----
80
- MHcCAQEEIBOQ3YIILYMV1glTKbF9oeZWzHe3SNQjAx4IbPIxNygQoAoGCCqGSM49
81
- AwEHoUQDQgAEuOC3ufTTnW0hVmCPNERb4LxaDE/OexDdlmXEjHYaixzYIduluGXd
82
- 3cjg4H2gjqsY/NCpJ9nM8/AAINSrq+qPuA==
83
- -----END EC PRIVATE KEY-----
84
- """
85
-
86
105
  conn = Faraday.new(url: URI.parse('http://example.com')) do |faraday|
87
106
  faraday.use JWTSignedRequest::Middlewares::Faraday,
88
- secret_key: OpenSSL::PKey::EC.new(private_key),
89
- algorithm: 'ES256', # optional (default: ES256)
90
- key_id: 'my-key-id', # optional
107
+ key_id: 'my-key-id',
91
108
  issuer: 'my-issuer', # optional
92
109
  additional_headers_to_sign: ['X-AUTH'] # optional
93
110
 
@@ -102,19 +119,13 @@ end
102
119
 
103
120
  ## Verifying Requests
104
121
 
105
- If you are using an asymmetrical encryption algorithm such as ES256 you will verify the request using the public key.
122
+ Please make sure you have added your verification keys to the key store. Doing so will allow the server to verify requests signed by different signing keys.
123
+
106
124
 
107
125
  ## Using Rails
108
126
 
109
127
  ```ruby
110
128
  class APIController < ApplicationController
111
- PUBLIC_KEY = """
112
- -----BEGIN PUBLIC KEY-----
113
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuOC3ufTTnW0hVmCPNERb4LxaDE/O
114
- exDdlmXEjHYaixzYIduluGXd3cjg4H2gjqsY/NCpJ9nM8/AAINSrq+qPuA==
115
- -----END PUBLIC KEY-----
116
- """
117
-
118
129
  before_action :verify_request
119
130
 
120
131
  ...
@@ -123,10 +134,7 @@ exDdlmXEjHYaixzYIduluGXd3cjg4H2gjqsY/NCpJ9nM8/AAINSrq+qPuA==
123
134
 
124
135
  def verify_request
125
136
  begin
126
- JWTSignedRequest.verify(
127
- request: request,
128
- secret_key: OpenSSL::PKey::EC.new(PUBLIC_KEY)
129
- )
137
+ JWTSignedRequest.verify(request: request)
130
138
 
131
139
  rescue JWTSignedRequest::UnauthorizedRequestError => e
132
140
  render :json => {}, :status => :unauthorized
@@ -141,26 +149,24 @@ end
141
149
  JWT tokens contain an expiry timestamp. If communication delays are large (or system clocks are sufficiently out of synch), you may need to increase the 'leeway' when verifying. For example:
142
150
 
143
151
  ```ruby
144
- JWTSignedRequest.verify(request: request, secret_key: 'my_public_key', leeway: 55)
152
+ JWTSignedRequest.verify(request: request, leeway: 55)
145
153
  ```
146
154
 
147
155
  ## Using Rack Middleware
148
156
 
149
157
  ```ruby
150
- PUBLIC_KEY = """
151
- -----BEGIN PUBLIC KEY-----
152
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuOC3ufTTnW0hVmCPNERb4LxaDE/O
153
- exDdlmXEjHYaixzYIduluGXd3cjg4H2gjqsY/NCpJ9nM8/AAINSrq+qPuA==
154
- -----END PUBLIC KEY-----
155
- """
156
-
157
158
  class Server < Sinatra::Base
158
159
  use JWTSignedRequest::Middlewares::Rack,
159
- secret_key: OpenSSL::PKey::EC.new(PUBLIC_KEY),
160
160
  exclude_paths: /public|health/ # optional regex
161
161
  end
162
162
  ```
163
163
 
164
+ ## Backwards Compability
165
+
166
+ Please note that the way we sign and verify requests has changed in version 2.x.x. For documentation on how to use older versions please look [here](https://github.com/envato/jwt_signed_request/blob/master/VERSION_1.md).
167
+
168
+ We are only supporting the old API for the next couple of releases of version 2.x.x so please upgrade ASAP.
169
+
164
170
  ## Maintainers
165
171
  - [Toan Nguyen](https://github.com/yoshdog)
166
172
 
@@ -4,19 +4,16 @@ require 'rack/utils'
4
4
 
5
5
  module JWTSignedRequest
6
6
  class Claims
7
- EMPTY_HEADERS = [].freeze
8
-
9
7
  def self.generate(args)
10
8
  new(**args).generate
11
9
  end
12
10
 
13
- def initialize(method:, path:, headers:, body:, additional_headers_to_sign: EMPTY_HEADERS, timeout: DEFAULT_TIMEOUT, issuer:)
11
+ def initialize(method:, path:, headers:, body:, additional_headers_to_sign:, issuer:)
14
12
  @method = method
15
13
  @path = path
16
- @headers = headers
14
+ @headers = headers || EMPTY_HEADERS
17
15
  @body = body
18
- @additional_headers_to_sign = additional_headers_to_sign
19
- @timeout = timeout
16
+ @additional_headers_to_sign = additional_headers_to_sign || EMPTY_HEADERS
20
17
  @issuer = issuer
21
18
  end
22
19
 
@@ -36,7 +33,7 @@ module JWTSignedRequest
36
33
 
37
34
  private
38
35
 
39
- attr_reader :method, :path, :headers, :body, :additional_headers_to_sign, :timeout, :issuer
36
+ attr_reader :method, :path, :headers, :body, :additional_headers_to_sign, :issuer
40
37
 
41
38
  HEADERS_TO_SIGN = %w(
42
39
  Content-Type
@@ -51,6 +48,14 @@ module JWTSignedRequest
51
48
 
52
49
  private_constant :DEFAULT_TIMEOUT
53
50
 
51
+ EMPTY_HEADERS = [].freeze
52
+
53
+ private_constant :EMPTY_HEADERS
54
+
55
+ def timeout
56
+ DEFAULT_TIMEOUT
57
+ end
58
+
54
59
  def formatted_body
55
60
  case body
56
61
  when String
@@ -0,0 +1,32 @@
1
+ module JWTSignedRequest
2
+ class KeyStore
3
+ def initialize
4
+ @signing_keys = {}
5
+ @verification_keys = {}
6
+ end
7
+
8
+ def add_signing_key(key_id:, key:, algorithm:)
9
+ @signing_keys.store(key_id,
10
+ {
11
+ key: key,
12
+ algorithm: algorithm
13
+ })
14
+ end
15
+
16
+ def add_verification_key(key_id:, key:, algorithm:)
17
+ @verification_keys.store(key_id,
18
+ {
19
+ key: key,
20
+ algorithm: algorithm
21
+ })
22
+ end
23
+
24
+ def get_signing_key(key_id:)
25
+ @signing_keys.fetch(key_id, {})
26
+ end
27
+
28
+ def get_verification_key(key_id:)
29
+ @verification_keys.fetch(key_id, {})
30
+ end
31
+ end
32
+ end
@@ -15,7 +15,6 @@ module JWTSignedRequest
15
15
  path: env[:url].request_uri,
16
16
  headers: env[:request_headers],
17
17
  body: env.fetch(:body, ::JWTSignedRequest::EMPTY_BODY),
18
- secret_key: options[:secret_key],
19
18
  **optional_settings
20
19
  )
21
20
 
@@ -29,6 +28,7 @@ module JWTSignedRequest
29
28
 
30
29
  def optional_settings
31
30
  {
31
+ secret_key: options[:secret_key],
32
32
  algorithm: options[:algorithm],
33
33
  additional_headers_to_sign: options[:additional_headers_to_sign],
34
34
  key_id: options[:key_id],
@@ -8,7 +8,7 @@ module JWTSignedRequest
8
8
 
9
9
  def initialize(app, options = {})
10
10
  @app = app
11
- @secret_key = options.fetch(:secret_key)
11
+ @secret_key = options[:secret_key]
12
12
  @algorithm = options[:algorithm]
13
13
  @exclude_paths = options[:exclude_paths]
14
14
  end
@@ -16,11 +16,13 @@ module JWTSignedRequest
16
16
  def call(env)
17
17
  begin
18
18
  unless excluded_path?(env)
19
- ::JWTSignedRequest.verify(
19
+ args = {
20
20
  request: ::Rack::Request.new(env),
21
21
  secret_key: secret_key,
22
22
  algorithm: algorithm
23
- )
23
+ }.reject { |_, value| value.nil? }
24
+
25
+ ::JWTSignedRequest.verify(**args)
24
26
  end
25
27
 
26
28
  app.call(env)
@@ -0,0 +1,68 @@
1
+ require 'jwt_signed_request/claims'
2
+
3
+ module JWTSignedRequest
4
+ class Sign
5
+ def self.call(*args)
6
+ new(*args).call
7
+ end
8
+
9
+ def initialize(
10
+ method:,
11
+ path:,
12
+ body: EMPTY_BODY,
13
+ headers:,
14
+ secret_key: nil,
15
+ algorithm: nil,
16
+ key_id: nil,
17
+ issuer: nil,
18
+ additional_headers_to_sign: nil
19
+ )
20
+ @method = method
21
+ @path = path
22
+ @body = body
23
+ @headers = headers
24
+ @secret_key = secret_key
25
+ @algorithm = algorithm
26
+ @key_id = key_id
27
+ @issuer = issuer
28
+ @additional_headers_to_sign = additional_headers_to_sign
29
+ end
30
+
31
+ def call
32
+ JWT.encode(claims, secret_key, algorithm, additional_jwt_headers)
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader \
38
+ :method, :path, :body, :headers,
39
+ :key_id, :issuer, :additional_headers_to_sign
40
+
41
+ def stored_key
42
+ @stored_key ||= JWTSignedRequest.key_store.get_signing_key(key_id: key_id)
43
+ end
44
+
45
+ def secret_key
46
+ @secret_key ||= stored_key.fetch(:key) { raise MissingKeyIdError }
47
+ end
48
+
49
+ def algorithm
50
+ @algorithm ||= stored_key.fetch(:algorithm, DEFAULT_ALGORITHM)
51
+ end
52
+
53
+ def additional_jwt_headers
54
+ key_id ? {kid: key_id} : {}
55
+ end
56
+
57
+ def claims
58
+ Claims.generate(
59
+ method: method,
60
+ path: path,
61
+ headers: headers,
62
+ body: body,
63
+ additional_headers_to_sign: additional_headers_to_sign,
64
+ issuer: issuer
65
+ )
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,96 @@
1
+ require 'jwt_signed_request/headers'
2
+
3
+ module JWTSignedRequest
4
+ class Verify
5
+ def self.call(*args)
6
+ new(*args).call
7
+ end
8
+
9
+ # TODO: secret_key & algorithm is deprecated and will be removed in future.
10
+ # For now we will support its functionaility
11
+ def initialize(request:, secret_key: nil, algorithm: nil, leeway: nil)
12
+ @request = request
13
+ @secret_key = secret_key
14
+ @algorithm = algorithm
15
+ @leeway = leeway
16
+ end
17
+
18
+ def call
19
+ if jwt_token.nil?
20
+ raise MissingAuthorizationHeaderError, "Missing Authorization header in the request"
21
+ end
22
+
23
+ unless verified_request?
24
+ raise RequestVerificationFailedError, "Request failed verification"
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :request, :leeway
31
+
32
+ def stored_key
33
+ jwt_header, _, _, _ = ::JWT.decoded_segments(jwt_token, false)
34
+ key_id = jwt_header.fetch('kid') { raise MissingKeyIdError }
35
+ signed_algorithm = jwt_header.fetch('alg')
36
+ JWTSignedRequest.key_store.get_verification_key(key_id: key_id).tap do |key|
37
+ if signed_algorithm != key[:algorithm]
38
+ raise AlgorithmMismatchError
39
+ end
40
+ end
41
+ end
42
+
43
+ def secret_key
44
+ @secret_key ||= stored_key.fetch(:key) { raise MissingKeyIdError }
45
+ end
46
+
47
+ def jwt_token
48
+ @jwt_token ||= Headers.fetch('Authorization', request)
49
+ end
50
+
51
+ def claims
52
+ @claims ||= begin
53
+ verify = true
54
+ options = {}
55
+
56
+ if leeway
57
+ # TODO: Once JWT v2.0.0 has been released, we should upgrade to it
58
+ # and start using `exp_leeway` instead 'leeway' will still work, but
59
+ # 'exp_leeway' is more explicit and is the documented way to do it.
60
+ #
61
+ # See https://github.com/jwt/ruby-jwt/pull/187.
62
+ options[:leeway] = leeway.to_i
63
+ end
64
+
65
+ JWT.decode(jwt_token, secret_key, verify, options)[0]
66
+ rescue ::JWT::DecodeError => e
67
+ raise JWTDecodeError, e.message
68
+ end
69
+ end
70
+
71
+ def verified_request?
72
+ claims['method'].to_s.downcase == request.request_method.downcase &&
73
+ claims['path'] == request.fullpath &&
74
+ claims['body_sha'] == Digest::SHA256.hexdigest(request_body) &&
75
+ verified_headers?
76
+ end
77
+
78
+ def request_body
79
+ string = request.body.read
80
+ request.body.rewind
81
+ string
82
+ end
83
+
84
+ def verified_headers?
85
+ parsed_headers = begin
86
+ JSON.parse(claims['headers'].to_s)
87
+ rescue JSON::ParserError
88
+ {}
89
+ end
90
+
91
+ parsed_headers.all? do |header_key, header_value|
92
+ Headers.fetch(header_key, request) == header_value
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,3 +1,3 @@
1
1
  module JWTSignedRequest
2
- VERSION = "1.2.2".freeze
2
+ VERSION = "2.0.0".freeze
3
3
  end
@@ -1,8 +1,11 @@
1
1
  require 'jwt'
2
- require 'jwt_signed_request/claims'
3
- require 'jwt_signed_request/headers'
2
+ require 'jwt_signed_request/key_store'
3
+ require 'jwt_signed_request/sign'
4
+ require 'jwt_signed_request/verify'
4
5
 
5
6
  module JWTSignedRequest
7
+ extend self
8
+
6
9
  DEFAULT_ALGORITHM = 'ES256'.freeze
7
10
  EMPTY_BODY = "".freeze
8
11
 
@@ -10,83 +13,23 @@ module JWTSignedRequest
10
13
  MissingAuthorizationHeaderError = Class.new(UnauthorizedRequestError)
11
14
  JWTDecodeError = Class.new(UnauthorizedRequestError)
12
15
  RequestVerificationFailedError = Class.new(UnauthorizedRequestError)
16
+ MissingKeyIdError = Class.new(UnauthorizedRequestError)
17
+ UnknownKeyIdError = Class.new(UnauthorizedRequestError)
18
+ AlgorithmMismatchError = Class.new(UnauthorizedRequestError)
13
19
 
14
- def self.sign(method:, path:,
15
- body: EMPTY_BODY, headers:,
16
- secret_key:, algorithm: DEFAULT_ALGORITHM,
17
- key_id: nil, issuer: nil,
18
- additional_headers_to_sign: Claims::EMPTY_HEADERS)
19
- additional_jwt_headers = key_id ? {kid: key_id} : {}
20
- JWT.encode(
21
- Claims.generate(
22
- method: method,
23
- path: path,
24
- headers: headers,
25
- body: body,
26
- additional_headers_to_sign: additional_headers_to_sign,
27
- issuer: issuer
28
- ),
29
- secret_key,
30
- algorithm,
31
- additional_jwt_headers
32
- )
33
- end
34
-
35
- def self.verify(request:, secret_key:, algorithm: nil, leeway: nil)
36
- # TODO: algorithm is deprecated and will be removed in future
37
- verify = true
38
- options = {}
39
- if leeway
40
- # TODO: Once JWT v2.0.0 has been released, we should upgrade to it and start using `exp_leeway` instead
41
- # 'leeway' will still work, but 'exp_leeway' is more explicit and is the documented way to do it.
42
- # see https://github.com/jwt/ruby-jwt/pull/187
43
- options[:leeway] = leeway.to_i
44
- end
45
- jwt_token = Headers.fetch('Authorization', request)
46
-
47
- if jwt_token.nil?
48
- raise MissingAuthorizationHeaderError, "Missing Authorization header in the request"
49
- end
50
-
51
- begin
52
- claims = JWT.decode(jwt_token, secret_key, verify, options)[0]
53
- unless verified_request?(request: request, claims: claims)
54
- raise RequestVerificationFailedError, "Request failed verification"
55
- end
56
-
57
- rescue ::JWT::DecodeError => e
58
- raise JWTDecodeError, e.message
59
- end
20
+ def configure_keys
21
+ yield(key_store)
60
22
  end
61
23
 
62
- def self.verified_request?(request:, claims:)
63
- claims['method'].to_s.downcase == request.request_method.downcase &&
64
- claims['path'] == request.fullpath &&
65
- claims['body_sha'] == Digest::SHA256.hexdigest(request_body(request: request)) &&
66
- verified_headers?(request: request, claims: claims)
24
+ def key_store
25
+ @key_store ||= KeyStore.new
67
26
  end
68
27
 
69
- private_class_method :verified_request?
70
-
71
- def self.request_body(request:)
72
- string = request.body.read
73
- request.body.rewind
74
- string
28
+ def sign(*args)
29
+ Sign.call(*args)
75
30
  end
76
31
 
77
- private_class_method :request_body
78
-
79
- def self.verified_headers?(request:, claims:)
80
- parsed_headers = begin
81
- JSON.parse(claims['headers'].to_s)
82
- rescue JSON::ParserError
83
- {}
84
- end
85
-
86
- parsed_headers.all? do |header_key, header_value|
87
- Headers.fetch(header_key, request) == header_value
88
- end
32
+ def verify(*args)
33
+ Verify.call(*args)
89
34
  end
90
-
91
- private_class_method :verified_headers?
92
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt_signed_request
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toan Nguyen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-11 00:00:00.000000000 Z
11
+ date: 2017-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt
@@ -119,8 +119,11 @@ files:
119
119
  - lib/jwt_signed_request.rb
120
120
  - lib/jwt_signed_request/claims.rb
121
121
  - lib/jwt_signed_request/headers.rb
122
+ - lib/jwt_signed_request/key_store.rb
122
123
  - lib/jwt_signed_request/middlewares/faraday.rb
123
124
  - lib/jwt_signed_request/middlewares/rack.rb
125
+ - lib/jwt_signed_request/sign.rb
126
+ - lib/jwt_signed_request/verify.rb
124
127
  - lib/jwt_signed_request/version.rb
125
128
  homepage: https://github.com/envato/jwt_signed_request
126
129
  licenses: []
@@ -141,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
144
  version: '0'
142
145
  requirements: []
143
146
  rubyforge_project:
144
- rubygems_version: 2.5.2
147
+ rubygems_version: 2.6.11
145
148
  signing_key:
146
149
  specification_version: 4
147
150
  summary: JWT request signing and verification for Internal APIs