jwt 2.4.1 → 2.8.1
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/CHANGELOG.md +102 -14
- data/CONTRIBUTING.md +7 -7
- data/README.md +154 -37
- data/lib/jwt/base64.rb +33 -0
- data/lib/jwt/claims_validator.rb +1 -1
- data/lib/jwt/configuration/container.rb +32 -0
- data/lib/jwt/configuration/decode_configuration.rb +46 -0
- data/lib/jwt/configuration/jwk_configuration.rb +27 -0
- data/lib/jwt/configuration.rb +15 -0
- data/lib/jwt/decode.rb +44 -29
- data/lib/jwt/deprecations.rb +29 -0
- data/lib/jwt/encode.rb +24 -20
- data/lib/jwt/error.rb +1 -0
- data/lib/jwt/{algos → jwa}/ecdsa.rb +19 -7
- data/lib/jwt/jwa/eddsa.rb +42 -0
- data/lib/jwt/jwa/hmac.rb +75 -0
- data/lib/jwt/jwa/hmac_rbnacl.rb +50 -0
- data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +46 -0
- data/lib/jwt/{algos → jwa}/none.rb +4 -2
- data/lib/jwt/jwa/ps.rb +30 -0
- data/lib/jwt/jwa/rsa.rb +25 -0
- data/lib/jwt/{algos → jwa}/unsupported.rb +1 -1
- data/lib/jwt/jwa/wrapper.rb +26 -0
- data/lib/jwt/jwa.rb +62 -0
- data/lib/jwt/jwk/ec.rb +160 -63
- data/lib/jwt/jwk/hmac.rb +69 -24
- data/lib/jwt/jwk/key_base.rb +45 -7
- data/lib/jwt/jwk/key_finder.rb +19 -35
- data/lib/jwt/jwk/kid_as_key_digest.rb +15 -0
- data/lib/jwt/jwk/okp_rbnacl.rb +110 -0
- data/lib/jwt/jwk/rsa.rb +141 -54
- data/lib/jwt/jwk/set.rb +80 -0
- data/lib/jwt/jwk/thumbprint.rb +26 -0
- data/lib/jwt/jwk.rb +14 -11
- data/lib/jwt/verify.rb +8 -4
- data/lib/jwt/version.rb +23 -1
- data/lib/jwt/x5c_key_finder.rb +1 -4
- data/lib/jwt.rb +6 -4
- data/ruby-jwt.gemspec +11 -4
- metadata +41 -27
- data/.codeclimate.yml +0 -8
- data/.github/workflows/coverage.yml +0 -27
- data/.github/workflows/test.yml +0 -66
- data/.gitignore +0 -13
- data/.reek.yml +0 -22
- data/.rspec +0 -2
- data/.rubocop.yml +0 -67
- data/.sourcelevel.yml +0 -17
- data/Appraisals +0 -13
- data/Gemfile +0 -7
- data/Rakefile +0 -16
- data/lib/jwt/algos/eddsa.rb +0 -33
- data/lib/jwt/algos/hmac.rb +0 -36
- data/lib/jwt/algos/ps.rb +0 -43
- data/lib/jwt/algos/rsa.rb +0 -22
- data/lib/jwt/algos.rb +0 -44
- data/lib/jwt/default_options.rb +0 -18
- data/lib/jwt/security_utils.rb +0 -59
- data/lib/jwt/signature.rb +0 -35
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: af3792b982f014801d3ff7ae3410be6bd1e0b27f199c500942eb86267bb2b764
|
|
4
|
+
data.tar.gz: c37fc4b72cf3819210b15164548eff44579de1e8f8c48d9ce35864a84f007d9a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f61fd13a1d56c657691abb4bfde3671a7d93b5c853785b804c0d119d27f4641685828eb9c65a8e4856487782530e791ecbce5f1a5f1cb61c883daff97a44367
|
|
7
|
+
data.tar.gz: ef36aa81991e28cb9d3df65f1ebbeb6599eb99dee8e1953aff1a6231e91c6a3f9633e3afd22fbbc6c09f6318c4e516ee7a908428eee303f3952fed890395b267
|
data/CHANGELOG.md
CHANGED
|
@@ -1,31 +1,119 @@
|
|
|
1
1
|
# Changelog
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
## [v2.8.1](https://github.com/jwt/ruby-jwt/tree/v2.8.1) (2024-02-29)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.8.0...v2.8.1)
|
|
6
|
+
|
|
7
|
+
**Features:**
|
|
8
|
+
|
|
9
|
+
- Configurable base64 decode behaviour [#589](https://github.com/jwt/ruby-jwt/pull/589) ([@anakinj](https://github.com/anakinj))
|
|
10
|
+
|
|
11
|
+
**Fixes and enhancements:**
|
|
12
|
+
|
|
13
|
+
- Output deprecation warnings once [#589](https://github.com/jwt/ruby-jwt/pull/589) ([@anakinj](https://github.com/anakinj))
|
|
14
|
+
|
|
15
|
+
## [v2.8.0](https://github.com/jwt/ruby-jwt/tree/v2.8.0) (2024-02-17)
|
|
16
|
+
|
|
17
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.1...v2.8.0)
|
|
18
|
+
|
|
19
|
+
**Features:**
|
|
20
|
+
|
|
21
|
+
- Updated rubocop to 1.56 [#573](https://github.com/jwt/ruby-jwt/pull/573) ([@anakinj](https://github.com/anakinj))
|
|
22
|
+
- Run CI on Ruby 3.3 [#577](https://github.com/jwt/ruby-jwt/pull/577) ([@anakinj](https://github.com/anakinj))
|
|
23
|
+
- 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))
|
|
24
|
+
- Stop using RbNaCl for standard HMAC algorithms [#575](https://github.com/jwt/ruby-jwt/pull/575) ([@anakinj](https://github.com/anakinj))
|
|
25
|
+
|
|
26
|
+
**Fixes and enhancements:**
|
|
27
|
+
|
|
28
|
+
- Fix signature has expired error if payload is a string [#555](https://github.com/jwt/ruby-jwt/pull/555) ([@GobinathAL](https://github.com/GobinathAL))
|
|
29
|
+
- Fix key base equality and spaceship operators [#569](https://github.com/jwt/ruby-jwt/pull/569) ([@magneland](https://github.com/magneland))
|
|
30
|
+
- Remove explicit base64 require from x5c_key_finder [#580](https://github.com/jwt/ruby-jwt/pull/580) ([@anakinj](https://github.com/anakinj))
|
|
31
|
+
- Performance improvements and cleanup of tests [#581](https://github.com/jwt/ruby-jwt/pull/581) ([@anakinj](https://github.com/anakinj))
|
|
32
|
+
- Repair EC x/y coordinates when importing JWK [#585](https://github.com/jwt/ruby-jwt/pull/585) ([@julik](https://github.com/julik))
|
|
33
|
+
- Explicit dependency to the base64 gem [#582](https://github.com/jwt/ruby-jwt/pull/582) ([@anakinj](https://github.com/anakinj))
|
|
34
|
+
- Deprecation warning for decoding content not compliant with RFC 4648 [#582](https://github.com/jwt/ruby-jwt/pull/582) ([@anakinj](https://github.com/anakinj))
|
|
35
|
+
- Algorithms moved under the `::JWT::JWA` module ([@anakinj](https://github.com/anakinj))
|
|
36
|
+
|
|
37
|
+
## [v2.7.1](https://github.com/jwt/ruby-jwt/tree/v2.8.0) (2023-06-09)
|
|
38
|
+
|
|
39
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.0...v2.7.1)
|
|
3
40
|
|
|
4
41
|
**Fixes and enhancements:**
|
|
5
|
-
|
|
42
|
+
|
|
43
|
+
- Handle invalid algorithm when decoding JWT [#559](https://github.com/jwt/ruby-jwt/pull/559) ([@nataliastanko](https://github.com/nataliastanko))
|
|
44
|
+
- Do not raise error when verifying bad HMAC signature [#563](https://github.com/jwt/ruby-jwt/pull/563) ([@hieuk09](https://github.com/hieuk09))
|
|
45
|
+
|
|
46
|
+
## [v2.7.0](https://github.com/jwt/ruby-jwt/tree/v2.7.0) (2023-02-01)
|
|
47
|
+
|
|
48
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.6.0...v2.7.0)
|
|
49
|
+
|
|
50
|
+
**Features:**
|
|
51
|
+
|
|
52
|
+
- Support OKP (Ed25519) keys for JWKs [#540](https://github.com/jwt/ruby-jwt/pull/540) ([@anakinj](https://github.com/anakinj))
|
|
53
|
+
- JWK Sets can now be used for tokens with nil kid [#543](https://github.com/jwt/ruby-jwt/pull/543) ([@bellebaum](https://github.com/bellebaum))
|
|
54
|
+
|
|
55
|
+
**Fixes and enhancements:**
|
|
56
|
+
|
|
57
|
+
- Fix issue with multiple keys returned by keyfinder and multiple allowed algorithms [#545](https://github.com/jwt/ruby-jwt/pull/545) ([@mpospelov](https://github.com/mpospelov))
|
|
58
|
+
- Non-string `kid` header values are now rejected [#543](https://github.com/jwt/ruby-jwt/pull/543) ([@bellebaum](https://github.com/bellebaum))
|
|
59
|
+
|
|
60
|
+
## [v2.6.0](https://github.com/jwt/ruby-jwt/tree/v2.6.0) (2022-12-22)
|
|
61
|
+
|
|
62
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.5.0...v2.6.0)
|
|
63
|
+
|
|
64
|
+
**Features:**
|
|
65
|
+
|
|
66
|
+
- Support custom algorithms by passing algorithm objects [#512](https://github.com/jwt/ruby-jwt/pull/512) ([@anakinj](https://github.com/anakinj))
|
|
67
|
+
- Support descriptive (not key related) JWK parameters [#520](https://github.com/jwt/ruby-jwt/pull/520) ([@bellebaum](https://github.com/bellebaum))
|
|
68
|
+
- Support for JSON Web Key Sets [#525](https://github.com/jwt/ruby-jwt/pull/525) ([@bellebaum](https://github.com/bellebaum))
|
|
69
|
+
- Support HMAC keys over 32 chars when using RbNaCl [#521](https://github.com/jwt/ruby-jwt/pull/521) ([@anakinj](https://github.com/anakinj))
|
|
70
|
+
|
|
71
|
+
**Fixes and enhancements:**
|
|
72
|
+
|
|
73
|
+
- 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))
|
|
74
|
+
|
|
75
|
+
## [v2.5.0](https://github.com/jwt/ruby-jwt/tree/v2.5.0) (2022-08-25)
|
|
76
|
+
|
|
77
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.4.1...v2.5.0)
|
|
78
|
+
|
|
79
|
+
**Features:**
|
|
80
|
+
|
|
81
|
+
- Support JWK thumbprints as key ids [#481](https://github.com/jwt/ruby-jwt/pull/481) ([@anakinj](https://github.com/anakinj))
|
|
82
|
+
- Support OpenSSL >= 3.0 [#496](https://github.com/jwt/ruby-jwt/pull/496) ([@anakinj](https://github.com/anakinj))
|
|
83
|
+
|
|
84
|
+
**Fixes and enhancements:**
|
|
85
|
+
- Bring back the old Base64 (RFC2045) deocode mechanisms [#488](https://github.com/jwt/ruby-jwt/pull/488) ([@anakinj](https://github.com/anakinj))
|
|
86
|
+
- Rescue RbNaCl exception for EdDSA wrong key [#491](https://github.com/jwt/ruby-jwt/pull/491) ([@n-studio](https://github.com/n-studio))
|
|
87
|
+
- 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))
|
|
88
|
+
- 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))
|
|
89
|
+
|
|
90
|
+
## [v2.4.1](https://github.com/jwt/ruby-jwt/tree/v2.4.1) (2022-06-07)
|
|
6
91
|
|
|
7
92
|
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.4.0...v2.4.1)
|
|
8
93
|
|
|
94
|
+
**Fixes and enhancements:**
|
|
95
|
+
- Raise JWT::DecodeError on invalid signature [\#484](https://github.com/jwt/ruby-jwt/pull/484) ([@freakyfelt!](https://github.com/freakyfelt!))
|
|
96
|
+
|
|
9
97
|
## [v2.4.0](https://github.com/jwt/ruby-jwt/tree/v2.4.0) (2022-06-06)
|
|
10
98
|
|
|
11
99
|
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.3.0...v2.4.0)
|
|
12
100
|
|
|
13
101
|
**Features:**
|
|
14
102
|
|
|
15
|
-
- Dropped support for Ruby 2.5 and older [#453](https://github.com/jwt/ruby-jwt/pull/453) - [@anakinj](https://github.com/anakinj)
|
|
16
|
-
- Use Ruby built-in url-safe base64 methods [#454](https://github.com/jwt/ruby-jwt/pull/454) - [@bdewater](https://github.com/bdewater)
|
|
17
|
-
- Updated rubocop to 1.23.0 [#457](https://github.com/jwt/ruby-jwt/pull/457) - [@anakinj](https://github.com/anakinj)
|
|
18
|
-
- Add x5c header key finder [#338](https://github.com/jwt/ruby-jwt/pull/338) - [@bdewater](https://github.com/bdewater)
|
|
19
|
-
- Author driven changelog process [#463](https://github.com/jwt/ruby-jwt/pull/463) - [@anakinj](https://github.com/anakinj)
|
|
20
|
-
- Allow regular expressions and procs to verify issuer [\#437](https://github.com/jwt/ruby-jwt/pull/437) ([rewritten](https://github.com/rewritten))
|
|
21
|
-
- Add Support to be able to verify from multiple keys [\#425](https://github.com/jwt/ruby-jwt/pull/425) ([ritikesh](https://github.com/ritikesh))
|
|
103
|
+
- Dropped support for Ruby 2.5 and older [#453](https://github.com/jwt/ruby-jwt/pull/453) - ([@anakinj](https://github.com/anakinj))
|
|
104
|
+
- Use Ruby built-in url-safe base64 methods [#454](https://github.com/jwt/ruby-jwt/pull/454) - ([@bdewater](https://github.com/bdewater))
|
|
105
|
+
- Updated rubocop to 1.23.0 [#457](https://github.com/jwt/ruby-jwt/pull/457) - ([@anakinj](https://github.com/anakinj))
|
|
106
|
+
- Add x5c header key finder [#338](https://github.com/jwt/ruby-jwt/pull/338) - ([@bdewater](https://github.com/bdewater))
|
|
107
|
+
- Author driven changelog process [#463](https://github.com/jwt/ruby-jwt/pull/463) - ([@anakinj](https://github.com/anakinj))
|
|
108
|
+
- Allow regular expressions and procs to verify issuer [\#437](https://github.com/jwt/ruby-jwt/pull/437) ([rewritten](https://github.com/rewritten))
|
|
109
|
+
- Add Support to be able to verify from multiple keys [\#425](https://github.com/jwt/ruby-jwt/pull/425) ([ritikesh](https://github.com/ritikesh))
|
|
22
110
|
|
|
23
111
|
**Fixes and enhancements:**
|
|
24
|
-
- Readme: Typo fix re MissingRequiredClaim [\#451](https://github.com/jwt/ruby-jwt/pull/451) ([antonmorant](https://github.com/antonmorant))
|
|
25
|
-
- Fix RuboCop TODOs [\#476](https://github.com/jwt/ruby-jwt/pull/476) ([typhoon2099](https://github.com/typhoon2099))
|
|
26
|
-
- Make specific algorithms in README linkable [\#472](https://github.com/jwt/ruby-jwt/pull/472) ([milieu](https://github.com/milieu))
|
|
27
|
-
- Update note about supported JWK types [\#475](https://github.com/jwt/ruby-jwt/pull/475) ([dpashkevich](https://github.com/dpashkevich))
|
|
28
|
-
- Create CODE\_OF\_CONDUCT.md [\#449](https://github.com/jwt/ruby-jwt/pull/449) ([loic5](https://github.com/loic5))
|
|
112
|
+
- Readme: Typo fix re MissingRequiredClaim [\#451](https://github.com/jwt/ruby-jwt/pull/451) ([antonmorant](https://github.com/antonmorant))
|
|
113
|
+
- Fix RuboCop TODOs [\#476](https://github.com/jwt/ruby-jwt/pull/476) ([typhoon2099](https://github.com/typhoon2099))
|
|
114
|
+
- Make specific algorithms in README linkable [\#472](https://github.com/jwt/ruby-jwt/pull/472) ([milieu](https://github.com/milieu))
|
|
115
|
+
- Update note about supported JWK types [\#475](https://github.com/jwt/ruby-jwt/pull/475) ([dpashkevich](https://github.com/dpashkevich))
|
|
116
|
+
- Create CODE\_OF\_CONDUCT.md [\#449](https://github.com/jwt/ruby-jwt/pull/449) ([loic5](https://github.com/loic5))
|
|
29
117
|
|
|
30
118
|
## [v2.3.0](https://github.com/jwt/ruby-jwt/tree/v2.3.0) (2021-10-03)
|
|
31
119
|
|
data/CONTRIBUTING.md
CHANGED
|
@@ -12,19 +12,19 @@ git remote add upstream https://github.com/jwt/ruby-jwt
|
|
|
12
12
|
|
|
13
13
|
## Create a branch for your implementation
|
|
14
14
|
|
|
15
|
-
Make sure you have the latest upstream
|
|
15
|
+
Make sure you have the latest upstream main branch of the project.
|
|
16
16
|
|
|
17
17
|
```
|
|
18
18
|
git fetch --all
|
|
19
|
-
git checkout
|
|
20
|
-
git rebase upstream/
|
|
21
|
-
git push origin
|
|
19
|
+
git checkout main
|
|
20
|
+
git rebase upstream/main
|
|
21
|
+
git push origin main
|
|
22
22
|
git checkout -b fix-a-little-problem
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## Running the tests and linter
|
|
26
26
|
|
|
27
|
-
Before you start with your implementation make sure you are able to get a
|
|
27
|
+
Before you start with your implementation make sure you are able to get a successful test run with the current revision.
|
|
28
28
|
|
|
29
29
|
The tests are written with rspec and [Appraisal](https://github.com/thoughtbot/appraisal) is used to ensure compatibility with 3rd party dependencies providing cryptographic features.
|
|
30
30
|
|
|
@@ -78,12 +78,12 @@ A maintainer will review and probably merge you changes when time allows, be pat
|
|
|
78
78
|
|
|
79
79
|
## Keeping your branch up-to-date
|
|
80
80
|
|
|
81
|
-
It's recommended that you keep your branch up-to-date by rebasing to the upstream
|
|
81
|
+
It's recommended that you keep your branch up-to-date by rebasing to the upstream main.
|
|
82
82
|
|
|
83
83
|
```
|
|
84
84
|
git fetch upstream
|
|
85
85
|
git checkout fix-a-little-problem
|
|
86
|
-
git rebase upstream/
|
|
86
|
+
git rebase upstream/main
|
|
87
87
|
git push origin fix-a-little-problem -f
|
|
88
88
|
```
|
|
89
89
|
|
data/README.md
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
# JWT
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/jwt)
|
|
4
|
-
[](https://github.com/jwt/ruby-jwt/actions)
|
|
5
5
|
[](https://codeclimate.com/github/jwt/ruby-jwt)
|
|
6
6
|
[](https://codeclimate.com/github/jwt/ruby-jwt/coverage)
|
|
7
7
|
[](https://codeclimate.com/github/jwt/ruby-jwt)
|
|
8
|
-
[](https://app.sourcelevel.io/github/jwt/-/ruby-jwt)
|
|
9
8
|
|
|
10
9
|
A ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) standard.
|
|
11
10
|
|
|
12
11
|
If you have further questions related to development or usage, join us: [ruby-jwt google group](https://groups.google.com/forum/#!forum/ruby-jwt).
|
|
13
12
|
|
|
14
13
|
## Announcements
|
|
15
|
-
* Ruby 2.4 support
|
|
14
|
+
* Ruby 2.4 support was dropped in version 2.4.0
|
|
16
15
|
* Ruby 1.9.3 support was dropped at December 31st, 2016.
|
|
17
16
|
* Version 1.5.3 yanked. See: [#132](https://github.com/jwt/ruby-jwt/issues/132) and [#133](https://github.com/jwt/ruby-jwt/issues/133)
|
|
18
17
|
|
|
@@ -44,6 +43,23 @@ The JWT spec supports NONE, HMAC, RSASSA, ECDSA and RSASSA-PSS algorithms for cr
|
|
|
44
43
|
|
|
45
44
|
See: [ JSON Web Algorithms (JWA) 3.1. "alg" (Algorithm) Header Parameter Values for JWS](https://tools.ietf.org/html/rfc7518#section-3.1)
|
|
46
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
|
+
|
|
47
63
|
### **NONE**
|
|
48
64
|
|
|
49
65
|
* none - unsigned token
|
|
@@ -73,12 +89,11 @@ puts decoded_token
|
|
|
73
89
|
### **HMAC**
|
|
74
90
|
|
|
75
91
|
* HS256 - HMAC using SHA-256 hash algorithm
|
|
76
|
-
* HS512256 - HMAC using SHA-512-256 hash algorithm (only available with RbNaCl; see note below)
|
|
77
92
|
* HS384 - HMAC using SHA-384 hash algorithm
|
|
78
93
|
* HS512 - HMAC using SHA-512 hash algorithm
|
|
79
94
|
|
|
80
95
|
```ruby
|
|
81
|
-
# The secret must be a string.
|
|
96
|
+
# The secret must be a string. With OpenSSL 3.0/openssl gem `<3.0.1`, JWT::DecodeError will be raised if it isn't provided.
|
|
82
97
|
hmac_secret = 'my$ecretK3y'
|
|
83
98
|
|
|
84
99
|
token = JWT.encode payload, hmac_secret, 'HS256'
|
|
@@ -96,12 +111,6 @@ decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' }
|
|
|
96
111
|
puts decoded_token
|
|
97
112
|
```
|
|
98
113
|
|
|
99
|
-
Note: If [RbNaCl](https://github.com/cryptosphere/rbnacl) is loadable, ruby-jwt will use it for HMAC-SHA256, HMAC-SHA512-256, and HMAC-SHA512. RbNaCl enforces a maximum key size of 32 bytes for these algorithms.
|
|
100
|
-
|
|
101
|
-
[RbNaCl](https://github.com/cryptosphere/rbnacl) requires
|
|
102
|
-
[libsodium](https://github.com/jedisct1/libsodium), it can be installed
|
|
103
|
-
on MacOS with `brew install libsodium`.
|
|
104
|
-
|
|
105
114
|
### **RSA**
|
|
106
115
|
|
|
107
116
|
* RS256 - RSA using SHA-256 hash algorithm
|
|
@@ -135,17 +144,14 @@ puts decoded_token
|
|
|
135
144
|
* ES256K - ECDSA using P-256K and SHA-256
|
|
136
145
|
|
|
137
146
|
```ruby
|
|
138
|
-
ecdsa_key = OpenSSL::PKey::EC.
|
|
139
|
-
ecdsa_key.generate_key
|
|
140
|
-
ecdsa_public = OpenSSL::PKey::EC.new ecdsa_key
|
|
141
|
-
ecdsa_public.private_key = nil
|
|
147
|
+
ecdsa_key = OpenSSL::PKey::EC.generate('prime256v1')
|
|
142
148
|
|
|
143
149
|
token = JWT.encode payload, ecdsa_key, 'ES256'
|
|
144
150
|
|
|
145
151
|
# eyJhbGciOiJFUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.AlLW--kaF7EX1NMX9WJRuIW8NeRJbn2BLXHns7Q5TZr7Hy3lF6MOpMlp7GoxBFRLISQ6KrD0CJOrR8aogEsPeg
|
|
146
152
|
puts token
|
|
147
153
|
|
|
148
|
-
decoded_token = JWT.decode token,
|
|
154
|
+
decoded_token = JWT.decode token, ecdsa_key, true, { algorithm: 'ES256' }
|
|
149
155
|
|
|
150
156
|
# Array
|
|
151
157
|
# [
|
|
@@ -163,7 +169,7 @@ In order to use this algorithm you need to add the `RbNaCl` gem to you `Gemfile`
|
|
|
163
169
|
gem 'rbnacl'
|
|
164
170
|
```
|
|
165
171
|
|
|
166
|
-
For more detailed installation instruction check the official [repository](https://github.com/
|
|
172
|
+
For more detailed installation instruction check the official [repository](https://github.com/RubyCrypto/rbnacl) on GitHub.
|
|
167
173
|
|
|
168
174
|
* ED25519
|
|
169
175
|
|
|
@@ -186,7 +192,7 @@ decoded_token = JWT.decode token, public_key, true, { algorithm: 'ED25519' }
|
|
|
186
192
|
|
|
187
193
|
### **RSASSA-PSS**
|
|
188
194
|
|
|
189
|
-
In order to use this algorithm you need to add the `openssl` gem to
|
|
195
|
+
In order to use this algorithm you need to add the `openssl` gem to your `Gemfile` with a version greater or equal to `2.1`.
|
|
190
196
|
|
|
191
197
|
```ruby
|
|
192
198
|
gem 'openssl', '~> 2.1'
|
|
@@ -215,6 +221,33 @@ decoded_token = JWT.decode token, rsa_public, true, { algorithm: 'PS256' }
|
|
|
215
221
|
puts decoded_token
|
|
216
222
|
```
|
|
217
223
|
|
|
224
|
+
### **Custom algorithms**
|
|
225
|
+
|
|
226
|
+
An object implementing custom signing or verification behaviour can be passed in the `algorithm` option when encoding and decoding. The given object needs to implement the method `valid_alg?` and `verify` and/or `alg` and `sign`, depending if object is used for encoding or decoding.
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
module CustomHS512Algorithm
|
|
230
|
+
def self.alg
|
|
231
|
+
'HS512'
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def self.valid_alg?(alg_to_validate)
|
|
235
|
+
alg_to_validate == alg
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def self.sign(data:, signing_key:)
|
|
239
|
+
OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha512'), data, signing_key)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def self.verify(data:, signature:, verification_key:)
|
|
243
|
+
::OpenSSL.secure_compare(sign(data: data, signing_key: verification_key), signature)
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
token = ::JWT.encode({'pay' => 'load'}, 'secret', CustomHS512Algorithm)
|
|
248
|
+
payload, header = ::JWT.decode(token, 'secret', true, algorithm: CustomHS512Algorithm)
|
|
249
|
+
```
|
|
250
|
+
|
|
218
251
|
## Support for reserved claim names
|
|
219
252
|
JSON Web Token defines some reserved claim names and defines how they should be
|
|
220
253
|
used. JWT supports these reserved claim names:
|
|
@@ -538,7 +571,7 @@ crls = crl_uris.map do |uri|
|
|
|
538
571
|
end
|
|
539
572
|
|
|
540
573
|
begin
|
|
541
|
-
JWT.decode(token, nil, true, { x5c: { root_certificates: root_certificates, crls: crls })
|
|
574
|
+
JWT.decode(token, nil, true, { x5c: { root_certificates: root_certificates, crls: crls } })
|
|
542
575
|
rescue JWT::DecodeError
|
|
543
576
|
# Handle error, e.g. x5c header certificate revoked or expired
|
|
544
577
|
end
|
|
@@ -546,22 +579,62 @@ end
|
|
|
546
579
|
|
|
547
580
|
### JSON Web Key (JWK)
|
|
548
581
|
|
|
549
|
-
JWK is a JSON structure representing a cryptographic key.
|
|
582
|
+
JWK is a JSON structure representing a cryptographic key. This gem currently supports RSA, EC, OKP and HMAC keys. OKP support requires [RbNaCl](https://github.com/RubyCrypto/rbnacl) and currently only supports the Ed25519 curve.
|
|
583
|
+
|
|
584
|
+
To encode a JWT using your JWK:
|
|
585
|
+
|
|
586
|
+
```ruby
|
|
587
|
+
optional_parameters = { kid: 'my-kid', use: 'sig', alg: 'RS512' }
|
|
588
|
+
jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), optional_parameters)
|
|
589
|
+
|
|
590
|
+
# Encoding
|
|
591
|
+
payload = { data: 'data' }
|
|
592
|
+
token = JWT.encode(payload, jwk.signing_key, jwk[:alg], kid: jwk[:kid])
|
|
593
|
+
|
|
594
|
+
# JSON Web Key Set for advertising your signing keys
|
|
595
|
+
jwks_hash = JWT::JWK::Set.new(jwk).export
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
To decode a JWT using a trusted entity's JSON Web Key Set (JWKS):
|
|
550
599
|
|
|
551
600
|
```ruby
|
|
552
|
-
|
|
553
|
-
|
|
601
|
+
jwks = JWT::JWK::Set.new(jwks_hash)
|
|
602
|
+
jwks.filter! {|key| key[:use] == 'sig' } # Signing keys only!
|
|
603
|
+
algorithms = jwks.map { |key| key[:alg] }.compact.uniq
|
|
604
|
+
JWT.decode(token, nil, true, algorithms: algorithms, jwks: jwks)
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
The `jwks` option can also be given as a lambda that evaluates every time a kid is resolved.
|
|
609
|
+
This can be used to implement caching of remotely fetched JWK Sets.
|
|
554
610
|
|
|
555
|
-
|
|
611
|
+
If the requested `kid` is not found from the given set the loader will be called a second time with the `kid_not_found` option set to `true`.
|
|
612
|
+
The application can choose to implement some kind of JWK cache invalidation or other mechanism to handle such cases.
|
|
556
613
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
614
|
+
Tokens without a specified `kid` are rejected by default.
|
|
615
|
+
This behaviour may be overwritten by setting the `allow_nil_kid` option for `decode` to `true`.
|
|
616
|
+
|
|
617
|
+
```ruby
|
|
618
|
+
jwks_loader = ->(options) do
|
|
619
|
+
# The jwk loader would fetch the set of JWKs from a trusted source.
|
|
620
|
+
# To avoid malicious requests triggering cache invalidations there needs to be
|
|
621
|
+
# some kind of grace time or other logic for determining the validity of the invalidation.
|
|
622
|
+
# This example only allows cache invalidations every 5 minutes.
|
|
623
|
+
if options[:kid_not_found] && @cache_last_update < Time.now.to_i - 300
|
|
624
|
+
logger.info("Invalidating JWK cache. #{options[:kid]} not found from previous cache")
|
|
625
|
+
@cached_keys = nil
|
|
626
|
+
end
|
|
627
|
+
@cached_keys ||= begin
|
|
628
|
+
@cache_last_update = Time.now.to_i
|
|
629
|
+
# Replace with your own JWKS fetching routine
|
|
630
|
+
jwks = JWT::JWK::Set.new(jwks_hash)
|
|
631
|
+
jwks.select! { |key| key[:use] == 'sig' } # Signing Keys only
|
|
632
|
+
jwks
|
|
633
|
+
end
|
|
561
634
|
end
|
|
562
635
|
|
|
563
636
|
begin
|
|
564
|
-
JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks:
|
|
637
|
+
JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwks_loader })
|
|
565
638
|
rescue JWT::JWKError
|
|
566
639
|
# Handle problems with the provided JWKs
|
|
567
640
|
rescue JWT::DecodeError
|
|
@@ -569,26 +642,70 @@ rescue JWT::DecodeError
|
|
|
569
642
|
end
|
|
570
643
|
```
|
|
571
644
|
|
|
572
|
-
|
|
645
|
+
### Importing and exporting JSON Web Keys
|
|
573
646
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
647
|
+
The ::JWT::JWK class can be used to import both JSON Web Keys and OpenSSL keys
|
|
648
|
+
and export to either format with and without the private key included.
|
|
649
|
+
|
|
650
|
+
To include the private key in the export pass the `include_private` parameter to the export method.
|
|
651
|
+
|
|
652
|
+
```ruby
|
|
653
|
+
# Import a JWK Hash (showing an HMAC example)
|
|
654
|
+
jwk = JWT::JWK.new({ kty: 'oct', k: 'my-secret', kid: 'my-kid' })
|
|
655
|
+
|
|
656
|
+
# Import an OpenSSL key
|
|
657
|
+
# You can optionally add descriptive parameters to the JWK
|
|
658
|
+
desc_params = { kid: 'my-kid', use: 'sig' }
|
|
659
|
+
jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), desc_params)
|
|
660
|
+
|
|
661
|
+
# Export as JWK Hash (public key only by default)
|
|
662
|
+
jwk_hash = jwk.export
|
|
663
|
+
jwk_hash_with_private_key = jwk.export(include_private: true)
|
|
664
|
+
|
|
665
|
+
# Export as OpenSSL key
|
|
666
|
+
public_key = jwk.verify_key
|
|
667
|
+
private_key = jwk.signing_key if jwk.private?
|
|
668
|
+
|
|
669
|
+
# You can also import and export entire JSON Web Key Sets
|
|
670
|
+
jwks_hash = { keys: [{ kty: 'oct', k: 'my-secret', kid: 'my-kid' }] }
|
|
671
|
+
jwks = JWT::JWK::Set.new(jwks_hash)
|
|
672
|
+
jwks_hash = jwks.export
|
|
577
673
|
```
|
|
578
674
|
|
|
579
|
-
###
|
|
675
|
+
### Key ID (kid) and JWKs
|
|
580
676
|
|
|
581
|
-
The
|
|
677
|
+
The key id (kid) generation in the gem is a custom algorithm and not based on any standards.
|
|
678
|
+
To use a standardized JWK thumbprint (RFC 7638) as the kid for JWKs a generator type can be specified in the global configuration
|
|
679
|
+
or can be given to the JWK instance on initialization.
|
|
582
680
|
|
|
583
681
|
```ruby
|
|
584
|
-
jwk =
|
|
682
|
+
JWT.configuration.jwk.kid_generator_type = :rfc7638_thumbprint
|
|
683
|
+
# OR
|
|
684
|
+
JWT.configuration.jwk.kid_generator = ::JWT::JWK::Thumbprint
|
|
685
|
+
# OR
|
|
686
|
+
jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), nil, kid_generator: ::JWT::JWK::Thumbprint)
|
|
585
687
|
|
|
586
688
|
jwk_hash = jwk.export
|
|
587
|
-
|
|
689
|
+
|
|
690
|
+
thumbprint_as_the_kid = jwk_hash[:kid]
|
|
588
691
|
```
|
|
589
692
|
|
|
590
|
-
|
|
693
|
+
# Development and Tests
|
|
694
|
+
|
|
695
|
+
We depend on [Bundler](http://rubygems.org/gems/bundler) for defining gemspec and performing releases to rubygems.org, which can be done with
|
|
591
696
|
|
|
697
|
+
```bash
|
|
698
|
+
rake release
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
The tests are written with rspec. [Appraisal](https://github.com/thoughtbot/appraisal) is used to ensure compatibility with 3rd party dependencies providing cryptographic features.
|
|
702
|
+
|
|
703
|
+
```bash
|
|
704
|
+
bundle install
|
|
705
|
+
bundle exec appraisal rake test
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
## How to contribute
|
|
592
709
|
See [CONTRIBUTING](CONTRIBUTING.md).
|
|
593
710
|
|
|
594
711
|
## Contributors
|
data/lib/jwt/base64.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
5
|
+
module JWT
|
|
6
|
+
# Base64 encoding and decoding
|
|
7
|
+
class Base64
|
|
8
|
+
class << self
|
|
9
|
+
# Encode a string with URL-safe Base64 complying with RFC 4648 (not padded).
|
|
10
|
+
def url_encode(str)
|
|
11
|
+
::Base64.urlsafe_encode64(str, padding: false)
|
|
12
|
+
end
|
|
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")
|
|
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')
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def loose_urlsafe_decode64(str)
|
|
28
|
+
str += '=' * (4 - str.length.modulo(4))
|
|
29
|
+
::Base64.decode64(str.tr('-_', '+/'))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/jwt/claims_validator.rb
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'decode_configuration'
|
|
4
|
+
require_relative 'jwk_configuration'
|
|
5
|
+
|
|
6
|
+
module JWT
|
|
7
|
+
module Configuration
|
|
8
|
+
class Container
|
|
9
|
+
attr_accessor :decode, :jwk, :strict_base64_decoding
|
|
10
|
+
attr_reader :deprecation_warnings
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
reset!
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def reset!
|
|
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
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JWT
|
|
4
|
+
module Configuration
|
|
5
|
+
class DecodeConfiguration
|
|
6
|
+
attr_accessor :verify_expiration,
|
|
7
|
+
:verify_not_before,
|
|
8
|
+
:verify_iss,
|
|
9
|
+
:verify_iat,
|
|
10
|
+
:verify_jti,
|
|
11
|
+
:verify_aud,
|
|
12
|
+
:verify_sub,
|
|
13
|
+
:leeway,
|
|
14
|
+
:algorithms,
|
|
15
|
+
:required_claims
|
|
16
|
+
|
|
17
|
+
def initialize
|
|
18
|
+
@verify_expiration = true
|
|
19
|
+
@verify_not_before = true
|
|
20
|
+
@verify_iss = false
|
|
21
|
+
@verify_iat = false
|
|
22
|
+
@verify_jti = false
|
|
23
|
+
@verify_aud = false
|
|
24
|
+
@verify_sub = false
|
|
25
|
+
@leeway = 0
|
|
26
|
+
@algorithms = ['HS256']
|
|
27
|
+
@required_claims = []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_h
|
|
31
|
+
{
|
|
32
|
+
verify_expiration: verify_expiration,
|
|
33
|
+
verify_not_before: verify_not_before,
|
|
34
|
+
verify_iss: verify_iss,
|
|
35
|
+
verify_iat: verify_iat,
|
|
36
|
+
verify_jti: verify_jti,
|
|
37
|
+
verify_aud: verify_aud,
|
|
38
|
+
verify_sub: verify_sub,
|
|
39
|
+
leeway: leeway,
|
|
40
|
+
algorithms: algorithms,
|
|
41
|
+
required_claims: required_claims
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../jwk/kid_as_key_digest'
|
|
4
|
+
require_relative '../jwk/thumbprint'
|
|
5
|
+
|
|
6
|
+
module JWT
|
|
7
|
+
module Configuration
|
|
8
|
+
class JwkConfiguration
|
|
9
|
+
def initialize
|
|
10
|
+
self.kid_generator_type = :key_digest
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def kid_generator_type=(value)
|
|
14
|
+
self.kid_generator = case value
|
|
15
|
+
when :key_digest
|
|
16
|
+
JWT::JWK::KidAsKeyDigest
|
|
17
|
+
when :rfc7638_thumbprint
|
|
18
|
+
JWT::JWK::Thumbprint
|
|
19
|
+
else
|
|
20
|
+
raise ArgumentError, "#{value} is not a valid kid generator type."
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
attr_accessor :kid_generator
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'configuration/container'
|
|
4
|
+
|
|
5
|
+
module JWT
|
|
6
|
+
module Configuration
|
|
7
|
+
def configure
|
|
8
|
+
yield(configuration)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def configuration
|
|
12
|
+
@configuration ||= ::JWT::Configuration::Container.new
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|