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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +93 -39
- data/bin/console +4 -0
- data/jwt-authorizer.gemspec +2 -0
- data/lib/jwt/authorizer.rb +11 -12
- data/lib/jwt/authorizer/version.rb +2 -2
- data/lib/jwt/{request_authorizer.rb → endpoint_token.rb} +9 -9
- data/lib/jwt/token.rb +13 -0
- data/lib/jwt/token/builder.rb +15 -0
- data/lib/jwt/token/claim.rb +32 -0
- data/lib/jwt/token/claim_builder.rb +48 -0
- data/lib/jwt/{authorizer → token}/configurable.rb +2 -6
- data/lib/jwt/{authorizer → token}/configuration.rb +1 -1
- data/lib/jwt/token/default_claims.rb +33 -0
- data/lib/jwt/token/verifier.rb +36 -0
- metadata +13 -11
- data/lib/jwt/authorizer/builder.rb +0 -21
- data/lib/jwt/authorizer/claim_validator.rb +0 -32
- data/lib/jwt/authorizer/validation.rb +0 -40
- data/lib/jwt/authorizer/verifier.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e324a064b198c930d1085ec1b633517467b9fb2d2acd5951be2c3613a17190b
|
4
|
+
data.tar.gz: d5f1aac2b3638c7ba12e74f74bd365463079140c5789a88da77cbd9c60e5abd7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23899cec2c6898756fdec308310cd39be9b3ba4da9c9537342678103502bb922a714645ed7c736b78d852abd123e926f1d8918af5f1e352d7ff4ee556ca0eb41
|
7
|
+
data.tar.gz: 4aa067249c8a651a8f1b68c6cd73f887350fe1ca10536e238912421cf34e0f3557ad4926cc7f0c0520eea83f8d6f220f33b4e6db8b090fda3ce848b6ac1a7d65
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
[](https://travis-ci.org/codesthq/jwt-authorizer) [](https://codeclimate.com/github/codesthq/jwt-authorizer/test_coverage) [](https://codeclimate.com/github/codesthq/jwt-authorizer/maintainability)
|
1
|
+
[](https://badge.fury.io/rb/jwt-authorizer) [](https://travis-ci.org/codesthq/jwt-authorizer) [](https://codeclimate.com/github/codesthq/jwt-authorizer/test_coverage) [](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
|
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::
|
27
|
+
You can configure your `JWT::Token` classes with `.configuration` and `.configure` options:
|
28
28
|
|
29
29
|
```ruby
|
30
|
-
JWT::
|
30
|
+
JWT::Token.configuration
|
31
31
|
|
32
|
-
JWT::
|
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::
|
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
|
47
|
+
Default claims can be overriden during instantiation of `JWT::Token` classes:
|
48
48
|
|
49
49
|
```ruby
|
50
|
-
JWT::
|
51
|
-
JWT::
|
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::
|
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::
|
60
|
-
|
61
|
-
|
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::
|
69
|
+
To verify token, use `JWT::Token.verify` method.
|
67
70
|
|
68
71
|
```ruby
|
69
|
-
|
70
|
-
token
|
71
|
-
JWT::
|
72
|
-
|
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::
|
77
|
+
JWT::Token.verify("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjB9.nooope")
|
76
78
|
# JWT::VerificationError: Signature verification raised
|
77
79
|
```
|
78
80
|
|
79
|
-
###
|
81
|
+
### Claims
|
80
82
|
|
81
|
-
You can use
|
83
|
+
You can use claims to define and verify non-standard claims.
|
82
84
|
|
83
85
|
```ruby
|
84
|
-
class
|
85
|
-
|
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.
|
91
|
-
|
92
|
-
|
93
|
-
missing_claim = "eyJhbGciOiJIUzI1NiJ9.
|
94
|
-
|
95
|
-
# JWT::
|
96
|
-
invalid_value = "eyJhbGciOiJIUzI1NiJ9.
|
97
|
-
|
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
|
106
|
+
You can pass additional context to claims:
|
104
107
|
|
105
108
|
```ruby
|
106
|
-
class
|
107
|
-
|
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
|
-
|
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
|
-
|
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/
|
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::
|
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
|
data/jwt-authorizer.gemspec
CHANGED
@@ -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"
|
data/lib/jwt/authorizer.rb
CHANGED
@@ -3,21 +3,20 @@
|
|
3
3
|
require "jwt/authorizer/version"
|
4
4
|
require "jwt"
|
5
5
|
|
6
|
-
require "jwt/
|
7
|
-
require "jwt/
|
8
|
-
require "jwt/
|
9
|
-
require "jwt/
|
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/
|
12
|
-
require "jwt/
|
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
|
-
|
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/
|
22
|
+
require "jwt/endpoint_token"
|
@@ -1,27 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module JWT
|
4
|
-
class
|
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
|
-
|
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
|
-
|
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,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
|
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
|
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
|
@@ -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.
|
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-
|
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/
|
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: '
|
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
|