jwt-authorizer 1.0.0.beta1 → 1.0.0.beta2

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
  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