jwt-authorizer 1.0.0.beta1 → 1.0.0.beta2

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: 428eced648fcb226781a748396f9bf30f3647af418ab5c6e059ef3312f92b416
4
- data.tar.gz: ec06ac75857191c25081b8a179067a1c216712b05c7bfb11b742f42d45d03509
3
+ metadata.gz: 6e324a064b198c930d1085ec1b633517467b9fb2d2acd5951be2c3613a17190b
4
+ data.tar.gz: d5f1aac2b3638c7ba12e74f74bd365463079140c5789a88da77cbd9c60e5abd7
5
5
  SHA512:
6
- metadata.gz: 12889b5f4b086638b400f5b7fe49182a68b06e054d80e97409334cc5f88a239fbabfdbb643bf1451f07f3b33ce222ce795cb7ab53025255ca17a9f618b9c1e0e
7
- data.tar.gz: 2a7d53727bd6d7defa4567f218c5b84914edbad8100ad9ea80e6bb281fa53444661c73c3989bf32c3ce4225bd64e50e21017e19a720a1e9e66ca21e5a77ab997
6
+ metadata.gz: 23899cec2c6898756fdec308310cd39be9b3ba4da9c9537342678103502bb922a714645ed7c736b78d852abd123e926f1d8918af5f1e352d7ff4ee556ca0eb41
7
+ data.tar.gz: 4aa067249c8a651a8f1b68c6cd73f887350fe1ca10536e238912421cf34e0f3557ad4926cc7f0c0520eea83f8d6f220f33b4e6db8b090fda3ce848b6ac1a7d65
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jwt-authorizer (1.0.0.beta1)
4
+ jwt-authorizer (1.0.0.beta2)
5
5
  jwt (~> 2.1)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- [![Build Status](https://travis-ci.org/codesthq/jwt-authorizer.svg?branch=master)](https://travis-ci.org/codesthq/jwt-authorizer) [![Test Coverage](https://api.codeclimate.com/v1/badges/5f975bb8720b7ee04326/test_coverage)](https://codeclimate.com/github/codesthq/jwt-authorizer/test_coverage) [![Maintainability](https://api.codeclimate.com/v1/badges/5f975bb8720b7ee04326/maintainability)](https://codeclimate.com/github/codesthq/jwt-authorizer/maintainability)
1
+ [![Gem Version](https://badge.fury.io/rb/jwt-authorizer.svg)](https://badge.fury.io/rb/jwt-authorizer) [![Build Status](https://travis-ci.org/codesthq/jwt-authorizer.svg?branch=master)](https://travis-ci.org/codesthq/jwt-authorizer) [![Test Coverage](https://api.codeclimate.com/v1/badges/5f975bb8720b7ee04326/test_coverage)](https://codeclimate.com/github/codesthq/jwt-authorizer/test_coverage) [![Maintainability](https://api.codeclimate.com/v1/badges/5f975bb8720b7ee04326/maintainability)](https://codeclimate.com/github/codesthq/jwt-authorizer/maintainability)
2
2
 
3
3
  # JWT::Authorizer
4
4
 
5
- `JWT::Authorizer` makes authorization with [JWT tokens](https://jwt.io/) simple. It allows creating and verifying JWT tokens according to rules (validations) set on specific `Authorizer` class.
5
+ `JWT::Authorizer` makes authorization with [JWT tokens](https://jwt.io/) simple. It allows creating and verifying JWT tokens according to claims set on specific `JWT::Token` class.
6
6
 
7
7
  ## Installation
8
8
 
@@ -24,19 +24,19 @@ Or install it yourself as:
24
24
 
25
25
  ### Configuration
26
26
 
27
- You can configure your `JWT::Authorizer` classes with `.configuration` and `.configure` options:
27
+ You can configure your `JWT::Token` classes with `.configuration` and `.configure` options:
28
28
 
29
29
  ```ruby
30
- JWT::Authorizer.configuration
30
+ JWT::Token.configuration
31
31
 
32
- JWT::Authorizer.configure do |config|
32
+ JWT::Token.configure do |config|
33
33
  config.expiry = 12 * 60 * 60
34
34
  config.algorithm = "RS256"
35
35
  config.secret = { private_key: nil, public_key: ENV["SECRET_KEY"] }
36
36
  end
37
37
  ```
38
38
 
39
- `JWT::Authorizer` have following options available:
39
+ `JWT::Token` have following options available:
40
40
 
41
41
  * `algorithm` - determines algorithm used on signing and verifying JWT tokens. Defaults to `"HS256"`.
42
42
  * `secret` - for [`HMAC`](https://en.wikipedia.org/wiki/HMAC) algorithms it accepts simple `String` with symmetric key, for [`RSA`](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) and [`ECDSA`](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) it requires hash with `:private_key` and `:public_key` keys.
@@ -44,75 +44,129 @@ end
44
44
  * `issuer` - sets `iss` claim in the token. Defaults to `nil`.
45
45
  * `allowed_issuers` - array of issuers that will be allowed on token verification. Defaults to empty array, tokens with any value in `iss` claim (and without this claim) will be valid. If array contains any elements, *only* listed issuers will be valid.
46
46
 
47
- Default options can be overriden during instantiation of `JWT::Authorizer` classes:
47
+ Default claims can be overriden during instantiation of `JWT::Token` classes:
48
48
 
49
49
  ```ruby
50
- JWT::Authorizer.configuration.expiry #=> 3600
51
- JWT::Authorizer.new(expiry: 60).expiry #=> 60
50
+ JWT::Token.configuration.expiry #=> 3600 (offset)
51
+ JWT::Token.new(expiry: Time.utc(2018, 3, 1)).expiry #=> 1519862400 (timestamp)
52
52
  ```
53
53
 
54
54
  ### Generating tokens
55
55
 
56
- To generate JWT token, create instance of `JWT::Authorizer` and call `#build` method. It accepts hash of additional claims you want in your token.
56
+ To generate JWT token, create instance of `JWT::Token`. It accepts hash of additional claims you want in your token.
57
57
 
58
58
  ```ruby
59
- JWT::Authorizer.configuration.secret = "hmac"
60
- JWT::Authorizer.new.build(level: :admin)
61
- #=> "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjAyODQ3MTcsImxldmVsIjoiYWRtaW4ifQ.nHRIBBjzteHuzygij-BlfXx3YIvfeO39Qh84hq729KQ"
59
+ class MyToken < JWT::Token
60
+ claim :level, required: true
61
+ end
62
+ token = MyToken.new(level: :admin)
63
+ token.to_s # or token.to_jwt
64
+ #=> "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0MTI2MTcsImxldmVsIjoiYWRtaW4ifQ.Ak8qDlxSG9IcPVHYnelQHPK5U6Rj5hBYQ5mmoznuYso"
62
65
  ```
63
66
 
64
67
  ### Verifying tokens
65
68
 
66
- To verify token, use `JWT::Authorizer#verify` method.
69
+ To verify token, use `JWT::Token.verify` method.
67
70
 
68
71
  ```ruby
69
- JWT::Authorizer.configuration.secret = "hmac"
70
- token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjAyODUwMzd9.CO8K_mqXCZfu8W12tpYcBo1WyrLZAmEMmr8R-HM3a5E"
71
- JWT::Authorizer.new.verify(token)
72
- #=> [{"exp"=>1520285037}, {"alg"=>"HS256"}]
73
- JWT::Authorizer.new.verify(nil)
72
+ token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0MTI2Nzd9.EgiqWfDjXzlJHTwaFn26X3iOl2gBkQv3fADtMsFIQDY"
73
+ JWT::Token.verify(token)
74
+ #=> #<JWT::Token @claims={"exp"=>1520412677, "iss"=>nil}>
75
+ JWT::Token.verify(nil)
74
76
  # JWT::DecodeError: Nil JSON web token
75
- JWT::Authorizer.new.verify("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjB9.nooope")
77
+ JWT::Token.verify("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjB9.nooope")
76
78
  # JWT::VerificationError: Signature verification raised
77
79
  ```
78
80
 
79
- ### Validators
81
+ ### Claims
80
82
 
81
- You can use validators to verify non-standard claims.
83
+ You can use claims to define and verify non-standard claims.
82
84
 
83
85
  ```ruby
84
- class AdminAuthorizer < JWT::Authorizer
85
- validate :level, required: true do |value, _context|
86
+ class AdminToken < JWT::Token
87
+ claim :level, key: "lvl", required: true do |value|
86
88
  raise JWT::DecodeError, "Level must be admin" unless value == "admin"
87
89
  end
88
90
  end
89
91
 
90
- valid_token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjAyODUzMzksImxldmVsIjoiYWRtaW4ifQ.OeIPSbtqlmcSJ1tUkLb7HhhMSlcAXKkrZhSOhgvYRHE"
91
- AdminAuthorizer.new.verify(valid_token)
92
- # [{"exp"=>1520285339, "level"=>"admin"}, {"alg"=>"HS256"}]
93
- missing_claim = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjAyODUzODd9.ncXmy81O64OjLNP4eCdAyVklAfGqdYiWp0K6FoI1pec"
94
- AdminAuthorizer.new.verify(missing_claim)
95
- # JWT::Authorizer::MissingClaim: Token is missing required claim: level
96
- invalid_value = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjAyODU0MzQsImxldmVsIjoicmVndWxhciJ9.z16nhJcOpRJmDZdkrDrdo1TetQ9YZpYiQmBdc53lnV0"
97
- AdminAuthorizer.new.verify(invalid_value)
92
+ valid_token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0MTI3ODksImxldmVsIjoiYWRtaW4ifQ.GGD0dXWg7v8BiEg8fsjmdCXQBryAHRpx_8AihyNVmgs"
93
+ AdminToken.verify(valid_token)
94
+ #=> #<AdminToken @claims={"exp"=>1520412789, "iss"=>nil, "lvl"=>"admin"}>
95
+ missing_claim = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0MTI3ODl9.efq_LuSpfp5VRwFl3rIf0FC_b2CCrpEC_oeDssvLDy4"
96
+ AdminToken.verify(missing_claim)
97
+ # JWT::Token::MissingClaim: Token is missing required claim: lvl
98
+ invalid_value = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0NTI3ODksImx2bCI6InJlZ3VsYXIifQ.EjXX9zhE4SpzFSlGIPD5l0xKtMKgWSbWa5smw3OvBEo"
99
+ AdminToken.verify(invalid_value)
98
100
  # JWT::DecodeError: Level must be admin
99
101
  ```
100
102
 
101
103
  `required` option is by default set to `false`. If set to `true`, given claim *must* be present in verified token.
104
+ `key` options is by default the same as claim name. It corresponds to JSON inside JWT.
102
105
 
103
- You can pass additional context to validators:
106
+ You can pass additional context to claims:
104
107
 
105
108
  ```ruby
106
- class AdminAuthorizer < JWT::Authorizer
107
- validate :path do |value, rack_request|
109
+ class AdminToken < JWT::Token
110
+ claim :path do |value, rack_request|
108
111
  raise JWT::DecodeError, "invalid path" unless value == rack_request.path
109
112
  end
110
113
  end
111
114
 
112
- AdminAuthorizer.new.verify(token, rack_request)
115
+ AdminToken.verify(token, rack_request)
116
+ ```
117
+
118
+ See [`JWT::EndpointToken`](lib/jwt/endpoint_token.rb) and it's [spec](spec/jwt/endpoint_token_spec.rb) for examples.
119
+
120
+ ### Default claims
121
+
122
+ Gem currently supports two of the standard claims: `exp` and `iss`.
123
+
124
+ #### Expiry
125
+
126
+ You can set `expiry` option on configuration to a preferred offset for generated tokens:
127
+
128
+ ```ruby
129
+ class LongLivedToken < JWT::Token
130
+ configuration.expiry = 2 * 365 * 24 * 60 * 60
131
+ end
132
+
133
+ token = LongLivedToken.new
134
+ Time.at token.expiry
135
+ #=> 2020-03-06 08:59:52 +0100
136
+ ```
137
+
138
+ Note that `expiry` option in configuration is an offset, while on token instance it's a timestamp.
139
+
140
+ On instance you can either assign timestamp, or a `Time` instance.
141
+
142
+ ```ruby
143
+ token = JWT::Token.new
144
+ token.expiry = Time.utc(2021, 1, 1)
145
+ token.expiry
146
+ #=> 1609459200
147
+
148
+ JWT::Token.new(expiry: Time.utc(2021, 1, 1)).expiry
149
+ #=> 1609459200
113
150
  ```
114
151
 
115
- See [`JWT::RequestAuthorizer`](lib/jwt/request_authorizer.rb) and it's [spec](spec/jwt/request_authorizer_spec.rb) for examples.
152
+ `exp` claim will be validated if present.
153
+
154
+ ### Issuer
155
+
156
+ In order to validate `issuer` claim, set `allowed_issuers` on token class:
157
+
158
+ ```ruby
159
+ class MicroserviceToken < JWT::Token
160
+ configuration.allowed_issuers = ["apiservice", "cronservice"]
161
+ end
162
+
163
+ MicroserviceToken.verify(MicroserviceToken.new(issuer: "apiservice").to_jwt)
164
+ #=> #<MicroserviceToken @claims={"exp"=>1520413510, "iss"=>"apiservice"}>
165
+ MicroserviceToken.verify(MicroserviceToken.new(issuer: "otherservice").to_jwt)
166
+ # JWT::InvalidIssuerError: Invalid issuer. Expected ["apiservice", "cronservice"], received otherservice
167
+ MicroserviceToken.verify(MicroserviceToken.new(issuer: nil).to_jwt)
168
+ # JWT::InvalidIssuerError: Invalid issuer. Expected ["apiservice", "cronservice"], received <none>
169
+ ```
116
170
 
117
171
  ## Development
118
172
 
@@ -122,7 +176,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
122
176
 
123
177
  ## Contributing
124
178
 
125
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/jwt-authorizer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
179
+ Bug reports and pull requests are welcome on GitHub at https://github.com/codesthq/jwt-authorizer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
126
180
 
127
181
  ## License
128
182
 
@@ -130,4 +184,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
130
184
 
131
185
  ## Code of Conduct
132
186
 
133
- Everyone interacting in the JWT::Authorizer project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/jwt-authorizer/blob/master/CODE_OF_CONDUCT.md).
187
+ Everyone interacting in the JWT::Token project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/codesthq/jwt-authorizer/blob/master/CODE_OF_CONDUCT.md).
data/bin/console CHANGED
@@ -7,5 +7,9 @@ require "jwt/authorizer"
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
9
9
 
10
+ JWT::Token.configure do |config|
11
+ config.secret = "hmac"
12
+ end
13
+
10
14
  require "pry"
11
15
  Pry.start
@@ -10,6 +10,8 @@ Gem::Specification.new do |spec|
10
10
  spec.authors = ["Michał Begejowicz"]
11
11
  spec.email = ["michal.begejowicz@codesthq.com"]
12
12
 
13
+ spec.required_ruby_version = "~> 2.4"
14
+
13
15
  spec.summary = "Authorization of requests for microservices based on JWT"
14
16
  spec.description = "Authorization of requests for microservices based on JWT"
15
17
  spec.homepage = "https://github.com/codesthq/jwt-authorizer"
@@ -3,21 +3,20 @@
3
3
  require "jwt/authorizer/version"
4
4
  require "jwt"
5
5
 
6
- require "jwt/authorizer/builder"
7
- require "jwt/authorizer/configuration"
8
- require "jwt/authorizer/configurable"
9
- require "jwt/authorizer/verifier"
6
+ require "jwt/token/builder"
7
+ require "jwt/token/configuration"
8
+ require "jwt/token/configurable"
9
+ require "jwt/token/verifier"
10
10
 
11
- require "jwt/authorizer/claim_validator"
12
- require "jwt/authorizer/validation"
11
+ require "jwt/token/default_claims"
12
+ require "jwt/token/claim"
13
+ require "jwt/token/claim_builder"
14
+
15
+ require "jwt/token"
13
16
 
14
17
  module JWT
15
- class Authorizer
16
- include Configurable
17
- include Builder
18
- include Verifier
19
- include Validation
18
+ module Authorizer
20
19
  end
21
20
  end
22
21
 
23
- require "jwt/request_authorizer"
22
+ require "jwt/endpoint_token"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
- class Authorizer
5
- VERSION = "1.0.0.beta1"
4
+ module Authorizer
5
+ VERSION = "1.0.0.beta2"
6
6
  end
7
7
  end
@@ -1,27 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
- class RequestAuthorizer < Authorizer
4
+ class EndpointToken < Token
5
5
  class << self
6
6
  attr_writer :token_extractor
7
7
 
8
8
  def token_extractor
9
9
  @token_extractor ||= proc { |req| req.env["X-Auth-Token"] || req.params["_t"] }
10
10
  end
11
+
12
+ def verify(rack_request)
13
+ token = token_extractor.call(rack_request)
14
+
15
+ super(token, rack_request)
16
+ end
11
17
  end
12
18
 
13
- validate :path, required: true do |value, rack_req|
19
+ claim :path, required: true do |value, rack_req|
14
20
  raise JWT::DecodeError, "Unexpected path: #{value}" unless value == rack_req.path
15
21
  end
16
22
 
17
- validate :verb, required: true do |value, rack_req|
23
+ claim :verb, required: true do |value, rack_req|
18
24
  raise JWT::DecodeError, "Unexpected request method: #{value}" unless value.to_s.upcase == rack_req.request_method
19
25
  end
20
-
21
- def verify(rack_request)
22
- token = self.class.token_extractor.call(rack_request)
23
-
24
- super(token, rack_request)
25
- end
26
26
  end
27
27
  end
data/lib/jwt/token.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ class Token
5
+ include Configurable
6
+
7
+ include DefaultClaims
8
+ include ClaimBuilder
9
+
10
+ include Builder
11
+ include Verifier
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ class Token
5
+ module Builder
6
+ def initialize(claims = {})
7
+ claims.each { |claim, value| send("#{claim}=", value) }
8
+ end
9
+
10
+ def to_jwt
11
+ JWT.encode claims.compact, secret[:private], algorithm
12
+ end; alias to_s to_jwt
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ class Token
5
+ class MissingClaim < JWT::DecodeError
6
+ attr_reader :claim
7
+
8
+ def initialize(claim)
9
+ @claim = claim
10
+ super("Token is missing required claim: #{claim}")
11
+ end
12
+ end
13
+
14
+ class Claim
15
+ attr_reader :name, :key, :required, :verifier
16
+
17
+ def initialize(name, key, required, verifier)
18
+ @name = name
19
+ @key = key
20
+ @required = required
21
+ @verifier = verifier
22
+ end
23
+
24
+ def verify(token, context = nil)
25
+ value = token.send(name)
26
+
27
+ raise(MissingClaim, key) if required && value.nil?
28
+ verifier.call(value, context) if value
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ class Token
5
+ module ClaimBuilder
6
+ class << self
7
+ def define_accessor_methods(token_class, claim)
8
+ define_getter(token_class, claim)
9
+ define_setter(token_class, claim)
10
+ end
11
+
12
+ def define_getter(token_class, claim)
13
+ token_class.send(:define_method, claim.name) { claims[claim.key] }
14
+ token_class.send(:alias_method, claim.key, claim.name)
15
+ end
16
+
17
+ def define_setter(token_class, claim)
18
+ method_name = "#{claim.name}="
19
+ token_class.send(:define_method, method_name) { |value| claims[claim.key] = value }
20
+ token_class.send(:alias_method, "#{claim.key}=", method_name)
21
+ end
22
+
23
+ def included(base)
24
+ base.extend(ClassMethods)
25
+ super
26
+ end
27
+ end
28
+
29
+ module ClassMethods
30
+ def inherited(subclass)
31
+ subclass.claims.concat(claims)
32
+ super
33
+ end
34
+
35
+ def claims
36
+ @claims ||= []
37
+ end
38
+
39
+ def claim(name, key: name.to_s, required: false, &verifier)
40
+ claim = JWT::Token::Claim.new(name, key, required, verifier).tap(&:freeze)
41
+
42
+ claims << claim
43
+ JWT::Token::ClaimBuilder.define_accessor_methods(self, claim)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
- class Authorizer
4
+ class Token
5
5
  module Configurable
6
6
  def self.included(base)
7
7
  base.extend(ClassMethods)
8
8
  base.extend(Forwardable)
9
- base.delegate %i[algorithm secret expiry issuer allowed_issuers] => :@config
10
- end
11
-
12
- def initialize(**options)
13
- @config = self.class.configuration.dup.merge(options)
9
+ base.delegate %i[algorithm secret allowed_issuers] => "self.class.configuration"
14
10
  end
15
11
 
16
12
  module ClassMethods
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
- class Authorizer
4
+ class Token
5
5
  class Configuration
6
6
  ATTRIBUTES = %i[algorithm secret expiry issuer allowed_issuers].freeze
7
7
 
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ class Token
5
+ module DefaultClaims
6
+ def expiry
7
+ claims["exp"]
8
+ end; alias exp expiry
9
+
10
+ def issuer
11
+ claims["iss"]
12
+ end; alias iss issuer
13
+
14
+ def expiry=(value)
15
+ claims["exp"] = value.is_a?(Time) ? value.to_i : value
16
+ end; alias exp= expiry=
17
+
18
+ def issuer=(value)
19
+ claims["iss"] = value
20
+ end; alias iss= issuer=
21
+
22
+ def claims
23
+ @claims ||= { "exp" => fetch_expiry, "iss" => self.class.configuration.issuer }
24
+ end
25
+
26
+ private
27
+
28
+ def fetch_expiry
29
+ (Time.now + self.class.configuration.expiry).to_i if self.class.configuration.expiry
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ class Token
5
+ module Verifier
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ super
9
+ end
10
+
11
+ module ClassMethods
12
+ def verify(jwt_token, context = nil)
13
+ decoded = JWT.decode(jwt_token, configuration.secret[:public], true, decode_options)
14
+
15
+ new(decoded[0]).tap do |token|
16
+ claims.each do |claim|
17
+ claim.verify(token, context)
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def decode_options
25
+ {}.tap do |result|
26
+ if configuration.allowed_issuers.any?
27
+ result[:iss] = configuration.allowed_issuers
28
+ result[:verify_iss] = true
29
+ end
30
+ result[:algorithm] = configuration.algorithm
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt-authorizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta1
4
+ version: 1.0.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michał Begejowicz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-06 00:00:00.000000000 Z
11
+ date: 2018-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt
@@ -159,14 +159,16 @@ files:
159
159
  - bin/setup
160
160
  - jwt-authorizer.gemspec
161
161
  - lib/jwt/authorizer.rb
162
- - lib/jwt/authorizer/builder.rb
163
- - lib/jwt/authorizer/claim_validator.rb
164
- - lib/jwt/authorizer/configurable.rb
165
- - lib/jwt/authorizer/configuration.rb
166
- - lib/jwt/authorizer/validation.rb
167
- - lib/jwt/authorizer/verifier.rb
168
162
  - lib/jwt/authorizer/version.rb
169
- - lib/jwt/request_authorizer.rb
163
+ - lib/jwt/endpoint_token.rb
164
+ - lib/jwt/token.rb
165
+ - lib/jwt/token/builder.rb
166
+ - lib/jwt/token/claim.rb
167
+ - lib/jwt/token/claim_builder.rb
168
+ - lib/jwt/token/configurable.rb
169
+ - lib/jwt/token/configuration.rb
170
+ - lib/jwt/token/default_claims.rb
171
+ - lib/jwt/token/verifier.rb
170
172
  homepage: https://github.com/codesthq/jwt-authorizer
171
173
  licenses:
172
174
  - MIT
@@ -177,9 +179,9 @@ require_paths:
177
179
  - lib
178
180
  required_ruby_version: !ruby/object:Gem::Requirement
179
181
  requirements:
180
- - - ">="
182
+ - - "~>"
181
183
  - !ruby/object:Gem::Version
182
- version: '0'
184
+ version: '2.4'
183
185
  required_rubygems_version: !ruby/object:Gem::Requirement
184
186
  requirements:
185
187
  - - ">"
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- class Authorizer
5
- module Builder
6
- def build(claims = {})
7
- payload = default_claims.merge!(claims)
8
- JWT.encode payload, secret[:private], algorithm
9
- end
10
-
11
- private
12
-
13
- def default_claims
14
- {}.tap do |result|
15
- result[:exp] = (Time.now + expiry).to_i if expiry
16
- result[:iss] = issuer if issuer
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- class Authorizer
5
- class MissingClaim < StandardError
6
- attr_reader :claim
7
-
8
- def initialize(claim)
9
- @claim = claim
10
- super("Token is missing required claim: #{claim}")
11
- end
12
- end
13
-
14
- class ClaimValidator
15
- attr_reader :name, :required, :verifier
16
-
17
- def initialize(name:, required: false, &block)
18
- @name = name.to_s
19
- @required = required
20
- @verifier = block
21
- end
22
-
23
- def validate(token, context)
24
- value = token.dig(0, name)
25
- raise MissingClaim, name if required && !value
26
- return unless value
27
-
28
- verifier.call(value, context)
29
- end
30
- end
31
- end
32
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- class Authorizer
5
- module Validation
6
- def self.included(base)
7
- base.extend(ClassMethods)
8
- end
9
-
10
- def verify(token, context = nil)
11
- super(token).tap do |decoded|
12
- validate_token(decoded, context)
13
- end
14
- end
15
-
16
- private
17
-
18
- def validate_token(token, context)
19
- self.class.validators.each do |validator|
20
- validator.validate(token, context)
21
- end
22
- end
23
-
24
- module ClassMethods
25
- def inherited(subclass)
26
- subclass.instance_variable_set("@validators", validators.dup)
27
- super
28
- end
29
-
30
- def validators
31
- @validators ||= []
32
- end
33
-
34
- def validate(claim_name, required: false, &block)
35
- validators << ClaimValidator.new(name: claim_name, required: required, &block)
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- class Authorizer
5
- module Verifier
6
- def verify(token)
7
- JWT.decode token, secret[:public], true, decode_options
8
- end
9
-
10
- private
11
-
12
- def decode_options
13
- {}.tap do |result|
14
- if allowed_issuers.any?
15
- result[:iss] = allowed_issuers
16
- result[:verify_iss] = true
17
- end
18
- result[:algorithm] = algorithm
19
- end
20
- end
21
- end
22
- end
23
- end