jwt 2.7.1 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +84 -27
- data/README.md +37 -19
- data/lib/jwt/base64.rb +16 -2
- data/lib/jwt/claims/audience.rb +20 -0
- data/lib/jwt/claims/expiration.rb +22 -0
- data/lib/jwt/claims/issued_at.rb +15 -0
- data/lib/jwt/claims/issuer.rb +24 -0
- data/lib/jwt/claims/jwt_id.rb +25 -0
- data/lib/jwt/claims/not_before.rb +22 -0
- data/lib/jwt/claims/numeric.rb +43 -0
- data/lib/jwt/claims/required.rb +23 -0
- data/lib/jwt/claims/subject.rb +20 -0
- data/lib/jwt/claims.rb +38 -0
- data/lib/jwt/configuration/container.rb +14 -3
- data/lib/jwt/configuration/jwk_configuration.rb +1 -1
- data/lib/jwt/decode.rb +12 -21
- data/lib/jwt/deprecations.rb +48 -0
- data/lib/jwt/encode.rb +4 -14
- data/lib/jwt/error.rb +1 -0
- data/lib/jwt/{algos → jwa}/ecdsa.rb +39 -26
- data/lib/jwt/jwa/eddsa.rb +34 -0
- data/lib/jwt/{algos → jwa}/hmac.rb +25 -19
- data/lib/jwt/jwa/hmac_rbnacl.rb +45 -0
- data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +42 -0
- data/lib/jwt/jwa/none.rb +23 -0
- data/lib/jwt/jwa/ps.rb +36 -0
- data/lib/jwt/jwa/rsa.rb +36 -0
- data/lib/jwt/jwa/signing_algorithm.rb +59 -0
- data/lib/jwt/jwa/unsupported.rb +19 -0
- data/lib/jwt/jwa/wrapper.rb +43 -0
- data/lib/jwt/jwa.rb +45 -0
- data/lib/jwt/jwk/ec.rb +42 -27
- data/lib/jwt/jwk/key_base.rb +3 -1
- data/lib/jwt/jwk/key_finder.rb +4 -4
- data/lib/jwt/jwk/set.rb +1 -1
- data/lib/jwt/jwk.rb +1 -1
- data/lib/jwt/version.rb +4 -3
- data/lib/jwt/x5c_key_finder.rb +2 -5
- data/lib/jwt.rb +5 -1
- data/ruby-jwt.gemspec +3 -0
- metadata +58 -20
- data/lib/jwt/algos/algo_wrapper.rb +0 -26
- data/lib/jwt/algos/eddsa.rb +0 -33
- data/lib/jwt/algos/hmac_rbnacl.rb +0 -53
- data/lib/jwt/algos/hmac_rbnacl_fixed.rb +0 -52
- data/lib/jwt/algos/none.rb +0 -19
- data/lib/jwt/algos/ps.rb +0 -41
- data/lib/jwt/algos/rsa.rb +0 -23
- data/lib/jwt/algos/unsupported.rb +0 -19
- data/lib/jwt/algos.rb +0 -66
- data/lib/jwt/claims_validator.rb +0 -37
- data/lib/jwt/verify.rb +0 -113
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f3d3ea752a6b4dee8f1b020a3e0af95e003f74a8c40f730faab73b616fc9e98
|
4
|
+
data.tar.gz: 8dcdb470771f56931485824c32739bfcec1ce310b7096d6cd28c656d0f8c21fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c68cccb66154a824751df6e7cd4d0b9d31372c0bada498097770feb8992ac3c7a462cd11eb759171d096e8d957b2a67b088fb35dc79fe7b4dd6eac6b25140d63
|
7
|
+
data.tar.gz: 03fe234584cce6458fb1a0f64cb399f81bc3c7aee40e25c011f0c27484ede3c6c6a6d950a9c5f3f13e4d66db5a76de98f2801942762df514097b2f663bf79247
|
data/CHANGELOG.md
CHANGED
@@ -1,13 +1,70 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v2.9.0](https://github.com/jwt/ruby-jwt/tree/v2.9.0) (NEXT)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.8.2...v2.9.0)
|
6
|
+
|
7
|
+
**Features:**
|
8
|
+
|
9
|
+
- Build and push gem using a GH action [#612](https://github.com/jwt/ruby-jwt/pull/612) ([@anakinj](https://github.com/anakinj))
|
10
|
+
|
11
|
+
**Fixes and enhancements:**
|
12
|
+
|
13
|
+
- Refactor claim validators into their own classes [#605](https://github.com/jwt/ruby-jwt/pull/605) ([@anakinj](https://github.com/anakinj), [@MatteoPierro](https://github.com/MatteoPierro))
|
14
|
+
- Allow extending available algorithms [#607](https://github.com/jwt/ruby-jwt/pull/607) ([@anakinj](https://github.com/anakinj))
|
15
|
+
- Do not include the EdDSA algorithm if rbnacl not available [#613](https://github.com/jwt/ruby-jwt/pull/613) ([@anakinj](https://github.com/anakinj))
|
16
|
+
|
17
|
+
## [v2.8.2](https://github.com/jwt/ruby-jwt/tree/v2.8.2) (2024-06-18)
|
18
|
+
|
19
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.8.1...v2.8.2)
|
20
|
+
|
21
|
+
**Fixes and enhancements:**
|
22
|
+
|
23
|
+
- Print deprecation warnings only on when token decoding succeeds [#600](https://github.com/jwt/ruby-jwt/pull/600) ([@anakinj](https://github.com/anakinj))
|
24
|
+
- Unify code style [#602](https://github.com/jwt/ruby-jwt/pull/602) ([@anakinj](https://github.com/anakinj))
|
25
|
+
|
26
|
+
## [v2.8.1](https://github.com/jwt/ruby-jwt/tree/v2.8.1) (2024-02-29)
|
27
|
+
|
28
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.8.0...v2.8.1)
|
29
|
+
|
30
|
+
**Features:**
|
31
|
+
|
32
|
+
- Configurable base64 decode behaviour [#589](https://github.com/jwt/ruby-jwt/pull/589) ([@anakinj](https://github.com/anakinj))
|
33
|
+
|
34
|
+
**Fixes and enhancements:**
|
35
|
+
|
36
|
+
- Output deprecation warnings once [#589](https://github.com/jwt/ruby-jwt/pull/589) ([@anakinj](https://github.com/anakinj))
|
37
|
+
|
38
|
+
## [v2.8.0](https://github.com/jwt/ruby-jwt/tree/v2.8.0) (2024-02-17)
|
39
|
+
|
40
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.1...v2.8.0)
|
41
|
+
|
42
|
+
**Features:**
|
43
|
+
|
44
|
+
- Updated rubocop to 1.56 [#573](https://github.com/jwt/ruby-jwt/pull/573) ([@anakinj](https://github.com/anakinj))
|
45
|
+
- Run CI on Ruby 3.3 [#577](https://github.com/jwt/ruby-jwt/pull/577) ([@anakinj](https://github.com/anakinj))
|
46
|
+
- Deprecation warning added for the HMAC algorithm HS512256 (HMAC-SHA-512 truncated to 256-bits) [#575](https://github.com/jwt/ruby-jwt/pull/575) ([@anakinj](https://github.com/anakinj))
|
47
|
+
- Stop using RbNaCl for standard HMAC algorithms [#575](https://github.com/jwt/ruby-jwt/pull/575) ([@anakinj](https://github.com/anakinj))
|
48
|
+
|
49
|
+
**Fixes and enhancements:**
|
50
|
+
|
51
|
+
- Fix signature has expired error if payload is a string [#555](https://github.com/jwt/ruby-jwt/pull/555) ([@GobinathAL](https://github.com/GobinathAL))
|
52
|
+
- Fix key base equality and spaceship operators [#569](https://github.com/jwt/ruby-jwt/pull/569) ([@magneland](https://github.com/magneland))
|
53
|
+
- Remove explicit base64 require from x5c_key_finder [#580](https://github.com/jwt/ruby-jwt/pull/580) ([@anakinj](https://github.com/anakinj))
|
54
|
+
- Performance improvements and cleanup of tests [#581](https://github.com/jwt/ruby-jwt/pull/581) ([@anakinj](https://github.com/anakinj))
|
55
|
+
- Repair EC x/y coordinates when importing JWK [#585](https://github.com/jwt/ruby-jwt/pull/585) ([@julik](https://github.com/julik))
|
56
|
+
- Explicit dependency to the base64 gem [#582](https://github.com/jwt/ruby-jwt/pull/582) ([@anakinj](https://github.com/anakinj))
|
57
|
+
- Deprecation warning for decoding content not compliant with RFC 4648 [#582](https://github.com/jwt/ruby-jwt/pull/582) ([@anakinj](https://github.com/anakinj))
|
58
|
+
- Algorithms moved under the `::JWT::JWA` module ([@anakinj](https://github.com/anakinj))
|
59
|
+
|
3
60
|
## [v2.7.1](https://github.com/jwt/ruby-jwt/tree/v2.8.0) (2023-06-09)
|
4
61
|
|
5
|
-
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.0...v2.
|
62
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.0...v2.7.1)
|
6
63
|
|
7
64
|
**Fixes and enhancements:**
|
8
65
|
|
9
|
-
- Handle invalid algorithm when decoding JWT [#559](https://github.com/jwt/ruby-jwt/pull/559)
|
10
|
-
- Do not raise error when verifying bad HMAC signature [#563](https://github.com/jwt/ruby-jwt/pull/563)
|
66
|
+
- Handle invalid algorithm when decoding JWT [#559](https://github.com/jwt/ruby-jwt/pull/559) ([@nataliastanko](https://github.com/nataliastanko))
|
67
|
+
- Do not raise error when verifying bad HMAC signature [#563](https://github.com/jwt/ruby-jwt/pull/563) ([@hieuk09](https://github.com/hieuk09))
|
11
68
|
|
12
69
|
## [v2.7.0](https://github.com/jwt/ruby-jwt/tree/v2.7.0) (2023-02-01)
|
13
70
|
|
@@ -29,14 +86,14 @@
|
|
29
86
|
|
30
87
|
**Features:**
|
31
88
|
|
32
|
-
- Support custom algorithms by passing algorithm objects[#512](https://github.com/jwt/ruby-jwt/pull/512) ([@anakinj](https://github.com/anakinj))
|
33
|
-
- Support descriptive (not key related) JWK parameters[#520](https://github.com/jwt/ruby-jwt/pull/520) ([@bellebaum](https://github.com/bellebaum))
|
34
|
-
- Support for JSON Web Key Sets[#525](https://github.com/jwt/ruby-jwt/pull/525) ([@bellebaum](https://github.com/bellebaum))
|
35
|
-
- Support HMAC keys over 32 chars when using RbNaCl[#521](https://github.com/jwt/ruby-jwt/pull/521) ([@anakinj](https://github.com/anakinj))
|
89
|
+
- Support custom algorithms by passing algorithm objects [#512](https://github.com/jwt/ruby-jwt/pull/512) ([@anakinj](https://github.com/anakinj))
|
90
|
+
- Support descriptive (not key related) JWK parameters [#520](https://github.com/jwt/ruby-jwt/pull/520) ([@bellebaum](https://github.com/bellebaum))
|
91
|
+
- Support for JSON Web Key Sets [#525](https://github.com/jwt/ruby-jwt/pull/525) ([@bellebaum](https://github.com/bellebaum))
|
92
|
+
- Support HMAC keys over 32 chars when using RbNaCl [#521](https://github.com/jwt/ruby-jwt/pull/521) ([@anakinj](https://github.com/anakinj))
|
36
93
|
|
37
94
|
**Fixes and enhancements:**
|
38
95
|
|
39
|
-
- Raise descriptive error on empty hmac_secret and OpenSSL 3.0/openssl gem <3.0.1 [#530](https://github.com/jwt/ruby-jwt/pull/530) ([@jonmchan](https://github.com/jonmchan))
|
96
|
+
- Raise descriptive error on empty hmac_secret and OpenSSL 3.0/openssl gem <3.0.1 [#530](https://github.com/jwt/ruby-jwt/pull/530) ([@jonmchan](https://github.com/jonmchan))
|
40
97
|
|
41
98
|
## [v2.5.0](https://github.com/jwt/ruby-jwt/tree/v2.5.0) (2022-08-25)
|
42
99
|
|
@@ -44,21 +101,21 @@
|
|
44
101
|
|
45
102
|
**Features:**
|
46
103
|
|
47
|
-
- Support JWK thumbprints as key ids [#481](https://github.com/jwt/ruby-jwt/pull/481) ([@anakinj](https://github.com/anakinj))
|
48
|
-
- Support OpenSSL >= 3.0 [#496](https://github.com/jwt/ruby-jwt/pull/496) ([@anakinj](https://github.com/anakinj))
|
104
|
+
- Support JWK thumbprints as key ids [#481](https://github.com/jwt/ruby-jwt/pull/481) ([@anakinj](https://github.com/anakinj))
|
105
|
+
- Support OpenSSL >= 3.0 [#496](https://github.com/jwt/ruby-jwt/pull/496) ([@anakinj](https://github.com/anakinj))
|
49
106
|
|
50
107
|
**Fixes and enhancements:**
|
51
|
-
- Bring back the old Base64 (RFC2045) deocode mechanisms [#488](https://github.com/jwt/ruby-jwt/pull/488) ([@anakinj](https://github.com/anakinj))
|
52
|
-
- Rescue RbNaCl exception for EdDSA wrong key [#491](https://github.com/jwt/ruby-jwt/pull/491) ([@n-studio](https://github.com/n-studio))
|
53
|
-
- New parameter name for cases when kid is not found using JWK key loader proc [#501](https://github.com/jwt/ruby-jwt/pull/501) ([@anakinj](https://github.com/anakinj))
|
54
|
-
- Fix NoMethodError when a 2 segment token is missing 'alg' header [#502](https://github.com/jwt/ruby-jwt/pull/502) ([@cmrd-senya](https://github.com/cmrd-senya))
|
108
|
+
- Bring back the old Base64 (RFC2045) deocode mechanisms [#488](https://github.com/jwt/ruby-jwt/pull/488) ([@anakinj](https://github.com/anakinj))
|
109
|
+
- Rescue RbNaCl exception for EdDSA wrong key [#491](https://github.com/jwt/ruby-jwt/pull/491) ([@n-studio](https://github.com/n-studio))
|
110
|
+
- New parameter name for cases when kid is not found using JWK key loader proc [#501](https://github.com/jwt/ruby-jwt/pull/501) ([@anakinj](https://github.com/anakinj))
|
111
|
+
- Fix NoMethodError when a 2 segment token is missing 'alg' header [#502](https://github.com/jwt/ruby-jwt/pull/502) ([@cmrd-senya](https://github.com/cmrd-senya))
|
55
112
|
|
56
113
|
## [v2.4.1](https://github.com/jwt/ruby-jwt/tree/v2.4.1) (2022-06-07)
|
57
114
|
|
58
115
|
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.4.0...v2.4.1)
|
59
116
|
|
60
117
|
**Fixes and enhancements:**
|
61
|
-
- Raise JWT::DecodeError on invalid signature [\#484](https://github.com/jwt/ruby-jwt/pull/484) ([@freakyfelt!](https://github.com/freakyfelt!))
|
118
|
+
- Raise JWT::DecodeError on invalid signature [\#484](https://github.com/jwt/ruby-jwt/pull/484) ([@freakyfelt!](https://github.com/freakyfelt!))
|
62
119
|
|
63
120
|
## [v2.4.0](https://github.com/jwt/ruby-jwt/tree/v2.4.0) (2022-06-06)
|
64
121
|
|
@@ -66,20 +123,20 @@
|
|
66
123
|
|
67
124
|
**Features:**
|
68
125
|
|
69
|
-
- Dropped support for Ruby 2.5 and older [#453](https://github.com/jwt/ruby-jwt/pull/453) - [@anakinj](https://github.com/anakinj)
|
70
|
-
- Use Ruby built-in url-safe base64 methods [#454](https://github.com/jwt/ruby-jwt/pull/454) - [@bdewater](https://github.com/bdewater)
|
71
|
-
- Updated rubocop to 1.23.0 [#457](https://github.com/jwt/ruby-jwt/pull/457) - [@anakinj](https://github.com/anakinj)
|
72
|
-
- Add x5c header key finder [#338](https://github.com/jwt/ruby-jwt/pull/338) - [@bdewater](https://github.com/bdewater)
|
73
|
-
- Author driven changelog process [#463](https://github.com/jwt/ruby-jwt/pull/463) - [@anakinj](https://github.com/anakinj)
|
74
|
-
- Allow regular expressions and procs to verify issuer [\#437](https://github.com/jwt/ruby-jwt/pull/437) ([rewritten](https://github.com/rewritten))
|
75
|
-
- Add Support to be able to verify from multiple keys [\#425](https://github.com/jwt/ruby-jwt/pull/425) ([ritikesh](https://github.com/ritikesh))
|
126
|
+
- Dropped support for Ruby 2.5 and older [#453](https://github.com/jwt/ruby-jwt/pull/453) - ([@anakinj](https://github.com/anakinj))
|
127
|
+
- Use Ruby built-in url-safe base64 methods [#454](https://github.com/jwt/ruby-jwt/pull/454) - ([@bdewater](https://github.com/bdewater))
|
128
|
+
- Updated rubocop to 1.23.0 [#457](https://github.com/jwt/ruby-jwt/pull/457) - ([@anakinj](https://github.com/anakinj))
|
129
|
+
- Add x5c header key finder [#338](https://github.com/jwt/ruby-jwt/pull/338) - ([@bdewater](https://github.com/bdewater))
|
130
|
+
- Author driven changelog process [#463](https://github.com/jwt/ruby-jwt/pull/463) - ([@anakinj](https://github.com/anakinj))
|
131
|
+
- Allow regular expressions and procs to verify issuer [\#437](https://github.com/jwt/ruby-jwt/pull/437) ([rewritten](https://github.com/rewritten))
|
132
|
+
- Add Support to be able to verify from multiple keys [\#425](https://github.com/jwt/ruby-jwt/pull/425) ([ritikesh](https://github.com/ritikesh))
|
76
133
|
|
77
134
|
**Fixes and enhancements:**
|
78
|
-
- Readme: Typo fix re MissingRequiredClaim [\#451](https://github.com/jwt/ruby-jwt/pull/451) ([antonmorant](https://github.com/antonmorant))
|
79
|
-
- Fix RuboCop TODOs [\#476](https://github.com/jwt/ruby-jwt/pull/476) ([typhoon2099](https://github.com/typhoon2099))
|
80
|
-
- Make specific algorithms in README linkable [\#472](https://github.com/jwt/ruby-jwt/pull/472) ([milieu](https://github.com/milieu))
|
81
|
-
- Update note about supported JWK types [\#475](https://github.com/jwt/ruby-jwt/pull/475) ([dpashkevich](https://github.com/dpashkevich))
|
82
|
-
- Create CODE\_OF\_CONDUCT.md [\#449](https://github.com/jwt/ruby-jwt/pull/449) ([loic5](https://github.com/loic5))
|
135
|
+
- Readme: Typo fix re MissingRequiredClaim [\#451](https://github.com/jwt/ruby-jwt/pull/451) ([antonmorant](https://github.com/antonmorant))
|
136
|
+
- Fix RuboCop TODOs [\#476](https://github.com/jwt/ruby-jwt/pull/476) ([typhoon2099](https://github.com/typhoon2099))
|
137
|
+
- Make specific algorithms in README linkable [\#472](https://github.com/jwt/ruby-jwt/pull/472) ([milieu](https://github.com/milieu))
|
138
|
+
- Update note about supported JWK types [\#475](https://github.com/jwt/ruby-jwt/pull/475) ([dpashkevich](https://github.com/dpashkevich))
|
139
|
+
- Create CODE\_OF\_CONDUCT.md [\#449](https://github.com/jwt/ruby-jwt/pull/449) ([loic5](https://github.com/loic5))
|
83
140
|
|
84
141
|
## [v2.3.0](https://github.com/jwt/ruby-jwt/tree/v2.3.0) (2021-10-03)
|
85
142
|
|
data/README.md
CHANGED
@@ -43,6 +43,23 @@ The JWT spec supports NONE, HMAC, RSASSA, ECDSA and RSASSA-PSS algorithms for cr
|
|
43
43
|
|
44
44
|
See: [ JSON Web Algorithms (JWA) 3.1. "alg" (Algorithm) Header Parameter Values for JWS](https://tools.ietf.org/html/rfc7518#section-3.1)
|
45
45
|
|
46
|
+
### Deprecation warnings
|
47
|
+
|
48
|
+
Deprecation warnings are logged once (`:once` option) by default to avoid spam in logs. Other options are `:silent` to completely silence warnings and `:warn` to log every time a deprecated path is executed.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
JWT.configuration.deprecation_warnings = :warn # default is :once
|
52
|
+
```
|
53
|
+
|
54
|
+
### Base64 decoding
|
55
|
+
|
56
|
+
In the past the gem has been supporting the Base64 decoding specified in [RFC2045](https://www.rfc-editor.org/rfc/rfc2045) allowing newlines and blanks in the base64 encoded payload. In future versions base64 decoding will be stricter and only comply to [RFC4648](https://www.rfc-editor.org/rfc/rfc4648).
|
57
|
+
|
58
|
+
The stricter base64 decoding when processing tokens can be done via the `strict_base64_decoding` configuration accessor.
|
59
|
+
```ruby
|
60
|
+
JWT.configuration.strict_base64_decoding = true # default is false
|
61
|
+
```
|
62
|
+
|
46
63
|
### **NONE**
|
47
64
|
|
48
65
|
* none - unsigned token
|
@@ -72,7 +89,6 @@ puts decoded_token
|
|
72
89
|
### **HMAC**
|
73
90
|
|
74
91
|
* HS256 - HMAC using SHA-256 hash algorithm
|
75
|
-
* HS512256 - HMAC using SHA-512-256 hash algorithm (only available with RbNaCl; see note below)
|
76
92
|
* HS384 - HMAC using SHA-384 hash algorithm
|
77
93
|
* HS512 - HMAC using SHA-512 hash algorithm
|
78
94
|
|
@@ -95,12 +111,6 @@ decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' }
|
|
95
111
|
puts decoded_token
|
96
112
|
```
|
97
113
|
|
98
|
-
Note: If [RbNaCl](https://github.com/RubyCrypto/rbnacl) is loadable, ruby-jwt will use it for HMAC-SHA256, HMAC-SHA512-256, and HMAC-SHA512. RbNaCl prior to 6.0.0 only support a maximum key size of 32 bytes for these algorithms.
|
99
|
-
|
100
|
-
[RbNaCl](https://github.com/RubyCrypto/rbnacl) requires
|
101
|
-
[libsodium](https://github.com/jedisct1/libsodium), it can be installed
|
102
|
-
on MacOS with `brew install libsodium`.
|
103
|
-
|
104
114
|
### **RSA**
|
105
115
|
|
106
116
|
* RS256 - RSA using SHA-256 hash algorithm
|
@@ -213,18 +223,22 @@ puts decoded_token
|
|
213
223
|
|
214
224
|
### **Custom algorithms**
|
215
225
|
|
216
|
-
|
226
|
+
When encoding or decoding a token, you can pass in a custom object through the `algorithm` option to handle signing or verification. This custom object must include or extend the `JWT::JWA::SigningAlgorithm` module and implement certain methods:
|
227
|
+
|
228
|
+
- For decoding/verifying: The object must implement the methods `alg` and `verify`.
|
229
|
+
- For encoding/signing: The object must implement the methods `alg` and `sign`.
|
230
|
+
|
231
|
+
For customization options check the details from `JWT::JWA::SigningAlgorithm`.
|
232
|
+
|
217
233
|
|
218
234
|
```ruby
|
219
235
|
module CustomHS512Algorithm
|
236
|
+
extend JWT::JWA::SigningAlgorithm
|
237
|
+
|
220
238
|
def self.alg
|
221
239
|
'HS512'
|
222
240
|
end
|
223
241
|
|
224
|
-
def self.valid_alg?(alg_to_validate)
|
225
|
-
alg_to_validate == alg
|
226
|
-
end
|
227
|
-
|
228
242
|
def self.sign(data:, signing_key:)
|
229
243
|
OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha512'), data, signing_key)
|
230
244
|
end
|
@@ -561,7 +575,7 @@ crls = crl_uris.map do |uri|
|
|
561
575
|
end
|
562
576
|
|
563
577
|
begin
|
564
|
-
JWT.decode(token, nil, true, { x5c: { root_certificates: root_certificates, crls: crls })
|
578
|
+
JWT.decode(token, nil, true, { x5c: { root_certificates: root_certificates, crls: crls } })
|
565
579
|
rescue JWT::DecodeError
|
566
580
|
# Handle error, e.g. x5c header certificate revoked or expired
|
567
581
|
end
|
@@ -680,21 +694,25 @@ jwk_hash = jwk.export
|
|
680
694
|
thumbprint_as_the_kid = jwk_hash[:kid]
|
681
695
|
```
|
682
696
|
|
683
|
-
# Development and
|
697
|
+
# Development and testing
|
684
698
|
|
685
|
-
|
699
|
+
The tests are written with rspec. [Appraisal](https://github.com/thoughtbot/appraisal) is used to ensure compatibility with 3rd party dependencies providing cryptographic features.
|
686
700
|
|
687
701
|
```bash
|
688
|
-
|
702
|
+
bundle install
|
703
|
+
bundle exec appraisal rake test
|
689
704
|
```
|
690
705
|
|
691
|
-
|
706
|
+
# Releasing
|
707
|
+
|
708
|
+
To cut a new release adjust the [version.rb](lib/jwt/version.rb) and [CHANGELOG](CHANGELOG.md) with desired version numbers and dates and commit the changes. Tag the release with the version number using the following command:
|
692
709
|
|
693
710
|
```bash
|
694
|
-
|
695
|
-
bundle exec appraisal rake test
|
711
|
+
rake release:source_control_push
|
696
712
|
```
|
697
713
|
|
714
|
+
This will tag a new version an trigger a [GitHub action](.github/workflows/push_gem.yml) that eventually will push the gem to rubygems.org.
|
715
|
+
|
698
716
|
## How to contribute
|
699
717
|
See [CONTRIBUTING](CONTRIBUTING.md).
|
700
718
|
|
data/lib/jwt/base64.rb
CHANGED
@@ -3,14 +3,28 @@
|
|
3
3
|
require 'base64'
|
4
4
|
|
5
5
|
module JWT
|
6
|
-
# Base64
|
6
|
+
# Base64 encoding and decoding
|
7
7
|
class Base64
|
8
8
|
class << self
|
9
|
+
# Encode a string with URL-safe Base64 complying with RFC 4648 (not padded).
|
9
10
|
def url_encode(str)
|
10
|
-
::Base64.
|
11
|
+
::Base64.urlsafe_encode64(str, padding: false)
|
11
12
|
end
|
12
13
|
|
14
|
+
# Decode a string with URL-safe Base64 complying with RFC 4648.
|
15
|
+
# Deprecated support for RFC 2045 remains for now. ("All line breaks or other characters not found in Table 1 must be ignored by decoding software")
|
13
16
|
def url_decode(str)
|
17
|
+
::Base64.urlsafe_decode64(str)
|
18
|
+
rescue ArgumentError => e
|
19
|
+
raise unless e.message == 'invalid base64'
|
20
|
+
raise Base64DecodeError, 'Invalid base64 encoding' if JWT.configuration.strict_base64_decoding
|
21
|
+
|
22
|
+
loose_urlsafe_decode64(str).tap do
|
23
|
+
Deprecations.warning('Invalid base64 input detected, could be because of invalid padding, trailing whitespaces or newline chars. Graceful handling of invalid input will be dropped in the next major version of ruby-jwt', only_if_valid: true)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def loose_urlsafe_decode64(str)
|
14
28
|
str += '=' * (4 - str.length.modulo(4))
|
15
29
|
::Base64.decode64(str.tr('-_', '+/'))
|
16
30
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
class Audience
|
6
|
+
def initialize(expected_audience:)
|
7
|
+
@expected_audience = expected_audience
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify!(context:, **_args)
|
11
|
+
aud = context.payload['aud']
|
12
|
+
raise JWT::InvalidAudError, "Invalid audience. Expected #{expected_audience}, received #{aud || '<none>'}" if ([*aud] & [*expected_audience]).empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :expected_audience
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
class Expiration
|
6
|
+
def initialize(leeway:)
|
7
|
+
@leeway = leeway || 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify!(context:, **_args)
|
11
|
+
return unless context.payload.is_a?(Hash)
|
12
|
+
return unless context.payload.key?('exp')
|
13
|
+
|
14
|
+
raise JWT::ExpiredSignature, 'Signature has expired' if context.payload['exp'].to_i <= (Time.now.to_i - leeway)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :leeway
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
class IssuedAt
|
6
|
+
def verify!(context:, **_args)
|
7
|
+
return unless context.payload.is_a?(Hash)
|
8
|
+
return unless context.payload.key?('iat')
|
9
|
+
|
10
|
+
iat = context.payload['iat']
|
11
|
+
raise(JWT::InvalidIatError, 'Invalid iat') if !iat.is_a?(::Numeric) || iat.to_f > Time.now.to_f
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
class Issuer
|
6
|
+
def initialize(issuers:)
|
7
|
+
@issuers = Array(issuers).map { |item| item.is_a?(Symbol) ? item.to_s : item }
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify!(context:, **_args)
|
11
|
+
case (iss = context.payload['iss'])
|
12
|
+
when *issuers
|
13
|
+
nil
|
14
|
+
else
|
15
|
+
raise JWT::InvalidIssuerError, "Invalid issuer. Expected #{issuers}, received #{iss || '<none>'}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :issuers
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
class JwtId
|
6
|
+
def initialize(validator:)
|
7
|
+
@validator = validator
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify!(context:, **_args)
|
11
|
+
jti = context.payload['jti']
|
12
|
+
if validator.respond_to?(:call)
|
13
|
+
verified = validator.arity == 2 ? validator.call(jti, context.payload) : validator.call(jti)
|
14
|
+
raise(JWT::InvalidJtiError, 'Invalid jti') unless verified
|
15
|
+
elsif jti.to_s.strip.empty?
|
16
|
+
raise(JWT::InvalidJtiError, 'Missing jti')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :validator
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
class NotBefore
|
6
|
+
def initialize(leeway:)
|
7
|
+
@leeway = leeway || 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify!(context:, **_args)
|
11
|
+
return unless context.payload.is_a?(Hash)
|
12
|
+
return unless context.payload.key?('nbf')
|
13
|
+
|
14
|
+
raise JWT::ImmatureSignature, 'Signature nbf has not been reached' if context.payload['nbf'].to_i > (Time.now.to_i + leeway)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :leeway
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
class Numeric
|
6
|
+
def self.verify!(payload:, **_args)
|
7
|
+
return unless payload.is_a?(Hash)
|
8
|
+
|
9
|
+
new(payload).verify!
|
10
|
+
end
|
11
|
+
|
12
|
+
NUMERIC_CLAIMS = %i[
|
13
|
+
exp
|
14
|
+
iat
|
15
|
+
nbf
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
def initialize(payload)
|
19
|
+
@payload = payload.transform_keys(&:to_sym)
|
20
|
+
end
|
21
|
+
|
22
|
+
def verify!
|
23
|
+
validate_numeric_claims
|
24
|
+
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def validate_numeric_claims
|
31
|
+
NUMERIC_CLAIMS.each do |claim|
|
32
|
+
validate_is_numeric(claim) if @payload.key?(claim)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate_is_numeric(claim)
|
37
|
+
return if @payload[claim].is_a?(::Numeric)
|
38
|
+
|
39
|
+
raise InvalidPayload, "#{claim} claim must be a Numeric value but it is a #{@payload[claim].class}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
class Required
|
6
|
+
def initialize(required_claims:)
|
7
|
+
@required_claims = required_claims
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify!(context:, **_args)
|
11
|
+
required_claims.each do |required_claim|
|
12
|
+
next if context.payload.is_a?(Hash) && context.payload.key?(required_claim)
|
13
|
+
|
14
|
+
raise JWT::MissingRequiredClaim, "Missing required claim #{required_claim}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :required_claims
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
class Subject
|
6
|
+
def initialize(expected_subject:)
|
7
|
+
@expected_subject = expected_subject.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify!(context:, **_args)
|
11
|
+
sub = context.payload['sub']
|
12
|
+
raise(JWT::InvalidSubError, "Invalid subject. Expected #{expected_subject}, received #{sub || '<none>'}") unless sub.to_s == expected_subject
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :expected_subject
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/jwt/claims.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'claims/audience'
|
4
|
+
require_relative 'claims/expiration'
|
5
|
+
require_relative 'claims/issued_at'
|
6
|
+
require_relative 'claims/issuer'
|
7
|
+
require_relative 'claims/jwt_id'
|
8
|
+
require_relative 'claims/not_before'
|
9
|
+
require_relative 'claims/numeric'
|
10
|
+
require_relative 'claims/required'
|
11
|
+
require_relative 'claims/subject'
|
12
|
+
|
13
|
+
module JWT
|
14
|
+
module Claims
|
15
|
+
VerificationContext = Struct.new(:payload, keyword_init: true)
|
16
|
+
|
17
|
+
VERIFIERS = {
|
18
|
+
verify_expiration: ->(options) { Claims::Expiration.new(leeway: options[:exp_leeway] || options[:leeway]) },
|
19
|
+
verify_not_before: ->(options) { Claims::NotBefore.new(leeway: options[:nbf_leeway] || options[:leeway]) },
|
20
|
+
verify_iss: ->(options) { Claims::Issuer.new(issuers: options[:iss]) },
|
21
|
+
verify_iat: ->(*) { Claims::IssuedAt.new },
|
22
|
+
verify_jti: ->(options) { Claims::JwtId.new(validator: options[:verify_jti]) },
|
23
|
+
verify_aud: ->(options) { Claims::Audience.new(expected_audience: options[:aud]) },
|
24
|
+
verify_sub: ->(options) { options[:sub] && Claims::Subject.new(expected_subject: options[:sub]) },
|
25
|
+
required_claims: ->(options) { Claims::Required.new(required_claims: options[:required_claims]) }
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def verify!(payload, options)
|
30
|
+
VERIFIERS.each do |key, verifier_builder|
|
31
|
+
next unless options[key]
|
32
|
+
|
33
|
+
verifier_builder&.call(options)&.verify!(context: VerificationContext.new(payload: payload))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -6,15 +6,26 @@ require_relative 'jwk_configuration'
|
|
6
6
|
module JWT
|
7
7
|
module Configuration
|
8
8
|
class Container
|
9
|
-
attr_accessor :decode, :jwk
|
9
|
+
attr_accessor :decode, :jwk, :strict_base64_decoding
|
10
|
+
attr_reader :deprecation_warnings
|
10
11
|
|
11
12
|
def initialize
|
12
13
|
reset!
|
13
14
|
end
|
14
15
|
|
15
16
|
def reset!
|
16
|
-
@decode
|
17
|
-
@jwk
|
17
|
+
@decode = DecodeConfiguration.new
|
18
|
+
@jwk = JwkConfiguration.new
|
19
|
+
@strict_base64_decoding = false
|
20
|
+
|
21
|
+
self.deprecation_warnings = :once
|
22
|
+
end
|
23
|
+
|
24
|
+
DEPRECATION_WARNINGS_VALUES = %i[once warn silent].freeze
|
25
|
+
def deprecation_warnings=(value)
|
26
|
+
raise ArgumentError, "Invalid deprecation_warnings value #{value}. Supported values: #{DEPRECATION_WARNINGS_VALUES}" unless DEPRECATION_WARNINGS_VALUES.include?(value)
|
27
|
+
|
28
|
+
@deprecation_warnings = value
|
18
29
|
end
|
19
30
|
end
|
20
31
|
end
|