jwt 2.4.0.beta1 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +15 -14
- data/.reek.yml +22 -0
- data/.rubocop.yml +9 -23
- data/.sourcelevel.yml +3 -4
- data/CHANGELOG.md +36 -37
- data/CONTRIBUTING.md +99 -0
- data/README.md +59 -30
- data/lib/jwt/algos/ecdsa.rb +22 -11
- data/lib/jwt/algos/eddsa.rb +2 -0
- data/lib/jwt/base64.rb +19 -0
- data/lib/jwt/configuration/container.rb +21 -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 +4 -4
- data/lib/jwt/encode.rb +2 -2
- data/lib/jwt/jwk/ec.rb +95 -46
- data/lib/jwt/jwk/hmac.rb +19 -10
- data/lib/jwt/jwk/key_base.rb +23 -7
- data/lib/jwt/jwk/key_finder.rb +1 -1
- data/lib/jwt/jwk/kid_as_key_digest.rb +15 -0
- data/lib/jwt/jwk/rsa.rb +54 -32
- data/lib/jwt/jwk/thumbprint.rb +26 -0
- data/lib/jwt/version.rb +7 -2
- data/lib/jwt/x5c_key_finder.rb +1 -1
- data/lib/jwt.rb +6 -5
- data/ruby-jwt.gemspec +2 -1
- metadata +29 -8
- data/.rubocop_todo.yml +0 -22
- data/lib/jwt/default_options.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3098671a837e7b291103cde1921277c61ecaa0f0797b955e6adc65328498f0d
|
4
|
+
data.tar.gz: 3253833ac6d7743e40a5d5157b161cd0daecc9b77f61dfa7687d6b3da1be56ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 306c946b1199301a3f1000c8ffba4a77d07fd05dd83f769da86fd29f254827b5af8488a4b6a54b11f1f7f3a028cb88caafb7ed67528e7004c0337f6506e595ea
|
7
|
+
data.tar.gz: 57d1eba7a06bc9d9f9fcb76b42aa3808415af5020c53969b4cada890b1646e7d348a96ce18010ab0a978e42825febbeb7b3f205b72e8ce60ef90132cf5887599
|
data/.github/workflows/test.yml
CHANGED
@@ -13,43 +13,44 @@ jobs:
|
|
13
13
|
timeout-minutes: 30
|
14
14
|
runs-on: ubuntu-latest
|
15
15
|
steps:
|
16
|
-
- uses: actions/checkout@
|
16
|
+
- uses: actions/checkout@v3
|
17
17
|
- name: Set up Ruby
|
18
18
|
uses: ruby/setup-ruby@v1
|
19
19
|
with:
|
20
|
-
ruby-version: "
|
20
|
+
ruby-version: "3.0"
|
21
21
|
bundler-cache: true
|
22
22
|
- name: Run RuboCop
|
23
23
|
run: bundle exec rubocop
|
24
24
|
test:
|
25
|
+
name: ${{ matrix.os }} - Ruby ${{ matrix.ruby }}
|
26
|
+
runs-on: ${{ matrix.os }}
|
25
27
|
strategy:
|
26
28
|
fail-fast: false
|
27
29
|
matrix:
|
30
|
+
os:
|
31
|
+
- ubuntu-20.04
|
28
32
|
ruby:
|
29
|
-
- 2.5
|
30
|
-
- 2.6
|
31
|
-
- 2.7
|
33
|
+
- "2.5"
|
34
|
+
- "2.6"
|
35
|
+
- "2.7"
|
32
36
|
- "3.0"
|
33
|
-
- 3.1
|
37
|
+
- "3.1"
|
34
38
|
gemfile:
|
35
39
|
- gemfiles/standalone.gemfile
|
36
40
|
- gemfiles/openssl.gemfile
|
37
41
|
- gemfiles/rbnacl.gemfile
|
38
42
|
experimental: [false]
|
39
43
|
include:
|
40
|
-
- ruby: 2.7
|
41
|
-
|
42
|
-
- ruby: "
|
43
|
-
|
44
|
-
- ruby: "truffleruby-head"
|
45
|
-
experimental: true
|
46
|
-
runs-on: ubuntu-20.04
|
44
|
+
- { os: ubuntu-20.04, ruby: "2.7", gemfile: 'gemfiles/rbnacl.gemfile', experimental: false }
|
45
|
+
- { os: ubuntu-22.04, ruby: "3.1", experimental: false }
|
46
|
+
- { os: ubuntu-20.04, ruby: "truffleruby-head", experimental: true }
|
47
|
+
- { os: ubuntu-22.04, ruby: "head", experimental: true }
|
47
48
|
continue-on-error: ${{ matrix.experimental }}
|
48
49
|
env:
|
49
50
|
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
50
51
|
|
51
52
|
steps:
|
52
|
-
- uses: actions/checkout@
|
53
|
+
- uses: actions/checkout@v3
|
53
54
|
|
54
55
|
- name: Install libsodium
|
55
56
|
run: |
|
data/.reek.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
---
|
2
|
+
detectors:
|
3
|
+
TooManyStatements:
|
4
|
+
max_statements: 10
|
5
|
+
UtilityFunction:
|
6
|
+
enabled: false
|
7
|
+
LongParameterList:
|
8
|
+
enabled: false
|
9
|
+
DuplicateMethodCall:
|
10
|
+
max_calls: 2
|
11
|
+
IrresponsibleModule:
|
12
|
+
enabled: false
|
13
|
+
NestedIterators:
|
14
|
+
max_allowed_nesting: 2
|
15
|
+
UnusedParameters:
|
16
|
+
enabled: false
|
17
|
+
FeatureEnvy:
|
18
|
+
enabled: false
|
19
|
+
ControlParameter:
|
20
|
+
enabled: false
|
21
|
+
UnusedPrivateMethod:
|
22
|
+
enabled: false
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
inherit_from: .rubocop_todo.yml
|
2
|
-
|
3
1
|
AllCops:
|
4
2
|
TargetRubyVersion: 2.5
|
5
3
|
NewCops: enable
|
@@ -21,43 +19,38 @@ Style/GuardClause:
|
|
21
19
|
Style/IfUnlessModifier:
|
22
20
|
Enabled: false
|
23
21
|
|
24
|
-
Layout/SpaceInsideHashLiteralBraces:
|
25
|
-
Enabled: false
|
26
|
-
|
27
22
|
Style/Lambda:
|
28
23
|
Enabled: false
|
29
24
|
|
30
25
|
Style/RaiseArgs:
|
31
26
|
Enabled: false
|
32
27
|
|
33
|
-
Style/SignalException:
|
34
|
-
Enabled: false
|
35
|
-
|
36
28
|
Metrics/AbcSize:
|
37
29
|
Max: 25
|
38
30
|
|
39
31
|
Metrics/ClassLength:
|
40
|
-
Max:
|
32
|
+
Max: 112
|
41
33
|
|
42
34
|
Metrics/ModuleLength:
|
43
35
|
Max: 100
|
44
36
|
|
45
|
-
|
46
|
-
|
37
|
+
Metrics/MethodLength:
|
38
|
+
Max: 20
|
47
39
|
|
48
40
|
Metrics/BlockLength:
|
49
41
|
Exclude:
|
50
42
|
- spec/**/*_spec.rb
|
51
43
|
|
52
|
-
|
53
|
-
Max: 15
|
54
|
-
|
55
|
-
Style/SingleLineBlockParams:
|
44
|
+
Layout/LineLength:
|
56
45
|
Enabled: false
|
57
46
|
|
58
47
|
Layout/EndAlignment:
|
59
48
|
EnforcedStyleAlignWith: variable
|
60
49
|
|
50
|
+
Layout/EmptyLineBetweenDefs:
|
51
|
+
Enabled: true
|
52
|
+
AllowAdjacentOneLineDefs: true
|
53
|
+
|
61
54
|
Style/FormatString:
|
62
55
|
Enabled: false
|
63
56
|
|
@@ -70,12 +63,5 @@ Layout/MultilineOperationIndentation:
|
|
70
63
|
Style/WordArray:
|
71
64
|
Enabled: false
|
72
65
|
|
73
|
-
|
66
|
+
Gemspec/RequireMFA:
|
74
67
|
Enabled: false
|
75
|
-
|
76
|
-
Layout/HashAlignment:
|
77
|
-
Enabled: true
|
78
|
-
EnforcedLastArgumentHashStyle: always_ignore
|
79
|
-
|
80
|
-
Style/TrivialAccessors:
|
81
|
-
AllowPredicates: true
|
data/.sourcelevel.yml
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
styleguide: excpt/linters
|
2
1
|
engines:
|
3
2
|
reek:
|
4
3
|
enabled: true
|
@@ -6,13 +5,13 @@ engines:
|
|
6
5
|
enabled: true
|
7
6
|
rubocop:
|
8
7
|
enabled: true
|
9
|
-
channel:
|
8
|
+
channel: latest
|
10
9
|
duplication:
|
11
10
|
config:
|
12
11
|
languages:
|
13
12
|
- ruby
|
14
13
|
enabled: true
|
15
14
|
remark-lint:
|
16
|
-
enabled:
|
15
|
+
enabled: false
|
17
16
|
exclude_paths:
|
18
|
-
- spec
|
17
|
+
- spec
|
data/CHANGELOG.md
CHANGED
@@ -1,51 +1,50 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [v2.4.0](https://github.com/jwt/ruby-jwt/tree/v2.4.0) (2022-05-03)
|
4
3
|
|
5
|
-
[
|
4
|
+
## [v2.5.0](https://github.com/jwt/ruby-jwt/tree/v2.5.0) (NEXT)
|
6
5
|
|
7
|
-
|
6
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.4.1...master)
|
8
7
|
|
9
|
-
|
10
|
-
- Support verifying signature signed using x5c header [\#59](https://github.com/jwt/ruby-jwt/issues/59)
|
11
|
-
- Add x5c header key finder [\#338](https://github.com/jwt/ruby-jwt/pull/338) ([bdewater](https://github.com/bdewater))
|
8
|
+
**Features:**
|
12
9
|
|
13
|
-
|
10
|
+
- Support JWK thumbprints as key ids [#481](https://github.com/jwt/ruby-jwt/pull/481) ([@anakinj](https://github.com/anakinj)).
|
11
|
+
- Your contribution here
|
14
12
|
|
15
|
-
|
13
|
+
**Fixes and enhancements:**
|
14
|
+
- Bring back the old Base64 (RFC2045) deocode mechanisms [#488](https://github.com/jwt/ruby-jwt/pull/488) ([@anakinj](https://github.com/anakinj)).
|
15
|
+
- Rescue RbNaCl exception for EdDSA wrong key [#491](https://github.com/jwt/ruby-jwt/pull/491) ([@n-studio](https://github.com/n-studio)).
|
16
|
+
- 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)).
|
17
|
+
- 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)).
|
18
|
+
- Support OpenSSL >= 3.0 [#496](https://github.com/jwt/ruby-jwt/pull/496) ([@anakinj](https://github.com/anakinj)).
|
19
|
+
- Your contribution here
|
16
20
|
|
17
|
-
|
21
|
+
## [v2.4.1](https://github.com/jwt/ruby-jwt/tree/v2.4.1) (2022-06-07)
|
18
22
|
|
19
|
-
|
20
|
-
- Encode output with extra quote [\#469](https://github.com/jwt/ruby-jwt/issues/469)
|
21
|
-
- Please release new gem version [\#444](https://github.com/jwt/ruby-jwt/issues/444)
|
22
|
-
- HS512 signature verification fails for valid tokens [\#438](https://github.com/jwt/ruby-jwt/issues/438)
|
23
|
-
- ArgumentError: invalid base64 while calling JWT::JWK.import\(hash\) [\#361](https://github.com/jwt/ruby-jwt/issues/361)
|
24
|
-
- NoMethodError (undefined method `encode' for JsonWebToken:Module\) [\#329](https://github.com/jwt/ruby-jwt/issues/329)
|
23
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.4.0...v2.4.1)
|
25
24
|
|
26
|
-
**
|
25
|
+
**Fixes and enhancements:**
|
26
|
+
- Raise JWT::DecodeError on invalid signature [\#484](https://github.com/jwt/ruby-jwt/pull/484) ([@freakyfelt!](https://github.com/freakyfelt!)).
|
27
|
+
|
28
|
+
## [v2.4.0](https://github.com/jwt/ruby-jwt/tree/v2.4.0) (2022-06-06)
|
29
|
+
|
30
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.3.0...v2.4.0)
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
-
|
31
|
-
-
|
32
|
-
-
|
33
|
-
-
|
34
|
-
-
|
35
|
-
-
|
36
|
-
-
|
37
|
-
|
38
|
-
|
39
|
-
-
|
40
|
-
-
|
41
|
-
-
|
42
|
-
-
|
43
|
-
-
|
44
|
-
- Fix for exception after mergeing \#385 [\#450](https://github.com/jwt/ruby-jwt/pull/450) ([anakinj](https://github.com/anakinj))
|
45
|
-
- Create CODE\_OF\_CONDUCT.md [\#449](https://github.com/jwt/ruby-jwt/pull/449) ([loic5](https://github.com/loic5))
|
46
|
-
- Allow regular expressions and procs to verify issuer [\#437](https://github.com/jwt/ruby-jwt/pull/437) ([rewritten](https://github.com/rewritten))
|
47
|
-
- Add Support to be able to verify from multiple keys [\#425](https://github.com/jwt/ruby-jwt/pull/425) ([ritikesh](https://github.com/ritikesh))
|
48
|
-
- Define the secp256r1 curve [\#385](https://github.com/jwt/ruby-jwt/pull/385) ([anakinj](https://github.com/anakinj))
|
32
|
+
**Features:**
|
33
|
+
|
34
|
+
- Dropped support for Ruby 2.5 and older [#453](https://github.com/jwt/ruby-jwt/pull/453) - [@anakinj](https://github.com/anakinj).
|
35
|
+
- Use Ruby built-in url-safe base64 methods [#454](https://github.com/jwt/ruby-jwt/pull/454) - [@bdewater](https://github.com/bdewater).
|
36
|
+
- Updated rubocop to 1.23.0 [#457](https://github.com/jwt/ruby-jwt/pull/457) - [@anakinj](https://github.com/anakinj).
|
37
|
+
- Add x5c header key finder [#338](https://github.com/jwt/ruby-jwt/pull/338) - [@bdewater](https://github.com/bdewater).
|
38
|
+
- Author driven changelog process [#463](https://github.com/jwt/ruby-jwt/pull/463) - [@anakinj](https://github.com/anakinj).
|
39
|
+
- Allow regular expressions and procs to verify issuer [\#437](https://github.com/jwt/ruby-jwt/pull/437) ([rewritten](https://github.com/rewritten)).
|
40
|
+
- Add Support to be able to verify from multiple keys [\#425](https://github.com/jwt/ruby-jwt/pull/425) ([ritikesh](https://github.com/ritikesh)).
|
41
|
+
|
42
|
+
**Fixes and enhancements:**
|
43
|
+
- Readme: Typo fix re MissingRequiredClaim [\#451](https://github.com/jwt/ruby-jwt/pull/451) ([antonmorant](https://github.com/antonmorant)).
|
44
|
+
- Fix RuboCop TODOs [\#476](https://github.com/jwt/ruby-jwt/pull/476) ([typhoon2099](https://github.com/typhoon2099)).
|
45
|
+
- Make specific algorithms in README linkable [\#472](https://github.com/jwt/ruby-jwt/pull/472) ([milieu](https://github.com/milieu)).
|
46
|
+
- Update note about supported JWK types [\#475](https://github.com/jwt/ruby-jwt/pull/475) ([dpashkevich](https://github.com/dpashkevich)).
|
47
|
+
- Create CODE\_OF\_CONDUCT.md [\#449](https://github.com/jwt/ruby-jwt/pull/449) ([loic5](https://github.com/loic5)).
|
49
48
|
|
50
49
|
## [v2.3.0](https://github.com/jwt/ruby-jwt/tree/v2.3.0) (2021-10-03)
|
51
50
|
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# Contributing to [ruby-jwt](https://github.com/jwt/ruby-jwt)
|
2
|
+
|
3
|
+
## Forking the project
|
4
|
+
|
5
|
+
Fork the project on GitHub and clone your own fork. Instuctions on forking can be found from the [GitHub Docs](https://docs.github.com/en/get-started/quickstart/fork-a-repo)
|
6
|
+
|
7
|
+
```
|
8
|
+
git clone git@github.com:you/ruby-jwt.git
|
9
|
+
cd ruby-jwt
|
10
|
+
git remote add upstream https://github.com/jwt/ruby-jwt
|
11
|
+
```
|
12
|
+
|
13
|
+
## Create a branch for your implementation
|
14
|
+
|
15
|
+
Make sure you have the latest upstream master branch of the project.
|
16
|
+
|
17
|
+
```
|
18
|
+
git fetch --all
|
19
|
+
git checkout master
|
20
|
+
git rebase upstream/master
|
21
|
+
git push origin master
|
22
|
+
git checkout -b fix-a-little-problem
|
23
|
+
```
|
24
|
+
|
25
|
+
## Running the tests and linter
|
26
|
+
|
27
|
+
Before you start with your implementation make sure you are able to get a succesful test run with the current revision.
|
28
|
+
|
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
|
+
|
31
|
+
[Rubocop](https://github.com/rubocop/rubocop) is used to enforce the Ruby style.
|
32
|
+
|
33
|
+
To run the complete set of tests and linter run the following
|
34
|
+
|
35
|
+
```bash
|
36
|
+
bundle install
|
37
|
+
bundle exec appraisal rake test
|
38
|
+
bundle exec rubocop
|
39
|
+
```
|
40
|
+
|
41
|
+
## Implement your feature
|
42
|
+
|
43
|
+
Implement tests and your change. Don't be shy adding a little something in the [README](README.md).
|
44
|
+
Add a short description of the change in either the `Features` or `Fixes` section in the [CHANGELOG](CHANGELOG.md) file.
|
45
|
+
|
46
|
+
The form of the row (You need to return to the row when you know the pull request id)
|
47
|
+
```
|
48
|
+
- Fix a little problem [#123](https://github.com/jwt/ruby-jwt/pull/123) - [@you](https://github.com/you).
|
49
|
+
```
|
50
|
+
|
51
|
+
## Push your branch and create a pull request
|
52
|
+
|
53
|
+
Before pushing make sure the tests pass and RuboCop is happy.
|
54
|
+
|
55
|
+
```
|
56
|
+
bundle exec appraisal rake test
|
57
|
+
bundle exec rubocop
|
58
|
+
git push origin fix-a-little-problem
|
59
|
+
```
|
60
|
+
|
61
|
+
Make a new pull request on the [ruby-jwt project](https://github.com/jwt/ruby-jwt/pulls) with a description what the change is about.
|
62
|
+
|
63
|
+
## Update the CHANGELOG, again
|
64
|
+
|
65
|
+
Update the [CHANGELOG](CHANGELOG.md) with the pull request id from the previous step.
|
66
|
+
|
67
|
+
You can ammend the previous commit with the updated changelog change and force push your branch. The PR will get automatically updated.
|
68
|
+
|
69
|
+
```
|
70
|
+
git add CHANGELOG.md
|
71
|
+
git commit --amend --no-edit
|
72
|
+
git push origin fix-a-little-problem -f
|
73
|
+
```
|
74
|
+
|
75
|
+
## Keep an eye on your pull request
|
76
|
+
|
77
|
+
A maintainer will review and probably merge you changes when time allows, be patient.
|
78
|
+
|
79
|
+
## Keeping your branch up-to-date
|
80
|
+
|
81
|
+
It's recommended that you keep your branch up-to-date by rebasing to the upstream master.
|
82
|
+
|
83
|
+
```
|
84
|
+
git fetch upstream
|
85
|
+
git checkout fix-a-little-problem
|
86
|
+
git rebase upstream/master
|
87
|
+
git push origin fix-a-little-problem -f
|
88
|
+
```
|
89
|
+
|
90
|
+
# Releasing a new version
|
91
|
+
|
92
|
+
The version is using the [Semantic Versioning](http://semver.org/) and the version is located in the [version.rb](lib/jwt/version.rb) file.
|
93
|
+
Also update the [CHANGELOG](CHANGELOG.md) to reflect the upcoming version release.
|
94
|
+
|
95
|
+
```bash
|
96
|
+
rake release
|
97
|
+
```
|
98
|
+
|
99
|
+
**If you want a release cut with your PR, please include a version bump according to **
|
data/README.md
CHANGED
@@ -12,10 +12,12 @@ A ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools
|
|
12
12
|
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
13
|
|
14
14
|
## Announcements
|
15
|
-
|
15
|
+
* Ruby 2.4 support was dropped in version 2.4.0
|
16
16
|
* Ruby 1.9.3 support was dropped at December 31st, 2016.
|
17
17
|
* 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
18
|
|
19
|
+
See [CHANGELOG.md](CHANGELOG.md) for a complete set of changes.
|
20
|
+
|
19
21
|
## Sponsors
|
20
22
|
|
21
23
|
|Logo|Message|
|
@@ -130,19 +132,17 @@ puts decoded_token
|
|
130
132
|
* ES256 - ECDSA using P-256 and SHA-256
|
131
133
|
* ES384 - ECDSA using P-384 and SHA-384
|
132
134
|
* ES512 - ECDSA using P-521 and SHA-512
|
135
|
+
* ES256K - ECDSA using P-256K and SHA-256
|
133
136
|
|
134
137
|
```ruby
|
135
|
-
ecdsa_key = OpenSSL::PKey::EC.
|
136
|
-
ecdsa_key.generate_key
|
137
|
-
ecdsa_public = OpenSSL::PKey::EC.new ecdsa_key
|
138
|
-
ecdsa_public.private_key = nil
|
138
|
+
ecdsa_key = OpenSSL::PKey::EC.generate('prime256v1')
|
139
139
|
|
140
140
|
token = JWT.encode payload, ecdsa_key, 'ES256'
|
141
141
|
|
142
142
|
# eyJhbGciOiJFUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.AlLW--kaF7EX1NMX9WJRuIW8NeRJbn2BLXHns7Q5TZr7Hy3lF6MOpMlp7GoxBFRLISQ6KrD0CJOrR8aogEsPeg
|
143
143
|
puts token
|
144
144
|
|
145
|
-
decoded_token = JWT.decode token,
|
145
|
+
decoded_token = JWT.decode token, ecdsa_key, true, { algorithm: 'ES256' }
|
146
146
|
|
147
147
|
# Array
|
148
148
|
# [
|
@@ -183,7 +183,7 @@ decoded_token = JWT.decode token, public_key, true, { algorithm: 'ED25519' }
|
|
183
183
|
|
184
184
|
### **RSASSA-PSS**
|
185
185
|
|
186
|
-
In order to use this algorithm you need to add the `openssl` gem to
|
186
|
+
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`.
|
187
187
|
|
188
188
|
```ruby
|
189
189
|
gem 'openssl', '~> 2.1'
|
@@ -543,30 +543,41 @@ end
|
|
543
543
|
|
544
544
|
### JSON Web Key (JWK)
|
545
545
|
|
546
|
-
JWK is a JSON structure representing a cryptographic key. Currently only supports RSA, EC and HMAC keys.
|
546
|
+
JWK is a JSON structure representing a cryptographic key. Currently only supports RSA, EC and HMAC keys. The `jwks` option can be given as a lambda that evaluates every time a kid is resolved.
|
547
547
|
|
548
|
-
|
549
|
-
jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), "optional-kid")
|
550
|
-
payload, headers = { data: 'data' }, { kid: jwk.kid }
|
548
|
+
If the 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`. The application can choose to implement some kind of JWK cache invalidation or other mechanism to handle such cases.
|
551
549
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
550
|
+
```ruby
|
551
|
+
jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), 'optional-kid')
|
552
|
+
payload = { data: 'data' }
|
553
|
+
headers = { kid: jwk.kid }
|
554
|
+
|
555
|
+
token = JWT.encode(payload, jwk.keypair, 'RS512', headers)
|
556
|
+
|
557
|
+
# The jwk loader would fetch the set of JWKs from a trusted source,
|
558
|
+
# to avoid malicious requests triggering cache invalidations there needs to be some kind of grace time or other logic for determining the validity of the invalidation.
|
559
|
+
# This example only allows cache invalidations every 5 minutes.
|
560
|
+
jwk_loader = ->(options) do
|
561
|
+
if options[:kid_not_found] && @cache_last_update < Time.now.to_i - 300
|
562
|
+
logger.info("Invalidating JWK cache. #{options[:kid]} not found from previous cache")
|
563
|
+
@cached_keys = nil
|
564
|
+
end
|
565
|
+
@cached_keys ||= begin
|
566
|
+
@cache_last_update = Time.now.to_i
|
567
|
+
{ keys: [jwk.export] }
|
568
|
+
end
|
569
|
+
end
|
559
570
|
|
560
|
-
begin
|
561
|
-
|
562
|
-
rescue JWT::JWKError
|
563
|
-
|
564
|
-
rescue JWT::DecodeError
|
565
|
-
|
566
|
-
end
|
571
|
+
begin
|
572
|
+
JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwk_loader })
|
573
|
+
rescue JWT::JWKError
|
574
|
+
# Handle problems with the provided JWKs
|
575
|
+
rescue JWT::DecodeError
|
576
|
+
# Handle other decode related issues e.g. no kid in header, no matching public key found etc.
|
577
|
+
end
|
567
578
|
```
|
568
579
|
|
569
|
-
or by passing
|
580
|
+
or by passing the JWKs as a simple Hash
|
570
581
|
|
571
582
|
```
|
572
583
|
jwks = { keys: [{ ... }] } # keys accepts both of string and symbol
|
@@ -575,7 +586,7 @@ JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwks})
|
|
575
586
|
|
576
587
|
### Importing and exporting JSON Web Keys
|
577
588
|
|
578
|
-
The ::JWT::JWK class can be used to import and export both the public key (default behaviour) and the private key. To include the private key in the export pass the
|
589
|
+
The ::JWT::JWK class can be used to import and export both the public key (default behaviour) and the private key. To include the private key in the export pass the `include_private` parameter to the export method.
|
579
590
|
|
580
591
|
```ruby
|
581
592
|
jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048))
|
@@ -584,6 +595,23 @@ jwk_hash = jwk.export
|
|
584
595
|
jwk_hash_with_private_key = jwk.export(include_private: true)
|
585
596
|
```
|
586
597
|
|
598
|
+
### Key ID (kid) and JWKs
|
599
|
+
|
600
|
+
The key id (kid) generation in the gem is a custom algorithm and not based on any standards. To use a standardized JWK thumbprint (RFC 7638) as the kid for JWKs a generator type can be specified in the global configuration or can be given to the JWK instance on initialization.
|
601
|
+
|
602
|
+
```ruby
|
603
|
+
JWT.configuration.jwk.kid_generator_type = :rfc7638_thumbprint
|
604
|
+
# OR
|
605
|
+
JWT.configuration.jwk.kid_generator = ::JWT::JWK::Thumbprint
|
606
|
+
# OR
|
607
|
+
jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), kid_generator: ::JWT::JWK::Thumbprint)
|
608
|
+
|
609
|
+
jwk_hash = jwk.export
|
610
|
+
|
611
|
+
thumbprint_as_the_kid = jwk_hash[:kid]
|
612
|
+
|
613
|
+
```
|
614
|
+
|
587
615
|
# Development and Tests
|
588
616
|
|
589
617
|
We depend on [Bundler](http://rubygems.org/gems/bundler) for defining gemspec and performing releases to rubygems.org, which can be done with
|
@@ -599,12 +627,13 @@ bundle install
|
|
599
627
|
bundle exec appraisal rake test
|
600
628
|
```
|
601
629
|
|
602
|
-
|
630
|
+
## How to contribute
|
631
|
+
See [CONTRIBUTING](CONTRIBUTING.md).
|
603
632
|
|
604
633
|
## Contributors
|
605
634
|
|
606
|
-
See
|
635
|
+
See [AUTHORS](AUTHORS).
|
607
636
|
|
608
637
|
## License
|
609
638
|
|
610
|
-
See
|
639
|
+
See [LICENSE](LICENSE).
|
data/lib/jwt/algos/ecdsa.rb
CHANGED
@@ -6,13 +6,29 @@ module JWT
|
|
6
6
|
module_function
|
7
7
|
|
8
8
|
NAMED_CURVES = {
|
9
|
-
'prime256v1' =>
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
'prime256v1' => {
|
10
|
+
algorithm: 'ES256',
|
11
|
+
digest: 'sha256'
|
12
|
+
},
|
13
|
+
'secp256r1' => { # alias for prime256v1
|
14
|
+
algorithm: 'ES256',
|
15
|
+
digest: 'sha256'
|
16
|
+
},
|
17
|
+
'secp384r1' => {
|
18
|
+
algorithm: 'ES384',
|
19
|
+
digest: 'sha384'
|
20
|
+
},
|
21
|
+
'secp521r1' => {
|
22
|
+
algorithm: 'ES512',
|
23
|
+
digest: 'sha512'
|
24
|
+
},
|
25
|
+
'secp256k1' => {
|
26
|
+
algorithm: 'ES256K',
|
27
|
+
digest: 'sha256'
|
28
|
+
}
|
13
29
|
}.freeze
|
14
30
|
|
15
|
-
SUPPORTED = NAMED_CURVES.
|
31
|
+
SUPPORTED = NAMED_CURVES.map { |_, c| c[:algorithm] }.uniq.freeze
|
16
32
|
|
17
33
|
def sign(to_sign)
|
18
34
|
algorithm, msg, key = to_sign.values
|
@@ -39,14 +55,9 @@ module JWT
|
|
39
55
|
end
|
40
56
|
|
41
57
|
def curve_by_name(name)
|
42
|
-
|
58
|
+
NAMED_CURVES.fetch(name) do
|
43
59
|
raise UnsupportedEcdsaCurve, "The ECDSA curve '#{name}' is not supported"
|
44
60
|
end
|
45
|
-
|
46
|
-
{
|
47
|
-
algorithm: algorithm,
|
48
|
-
digest: algorithm.sub('ES', 'sha')
|
49
|
-
}
|
50
61
|
end
|
51
62
|
end
|
52
63
|
end
|
data/lib/jwt/algos/eddsa.rb
CHANGED
@@ -27,6 +27,8 @@ module JWT
|
|
27
27
|
raise DecodeError, "key given is a #{public_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey" if public_key.class != RbNaCl::Signatures::Ed25519::VerifyKey
|
28
28
|
|
29
29
|
public_key.verify(signature, signing_input)
|
30
|
+
rescue RbNaCl::CryptoError
|
31
|
+
false
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
data/lib/jwt/base64.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module JWT
|
6
|
+
# Base64 helpers
|
7
|
+
class Base64
|
8
|
+
class << self
|
9
|
+
def url_encode(str)
|
10
|
+
::Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '')
|
11
|
+
end
|
12
|
+
|
13
|
+
def url_decode(str)
|
14
|
+
str += '=' * (4 - str.length.modulo(4))
|
15
|
+
::Base64.decode64(str.tr('-_', '+/'))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
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
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
reset!
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset!
|
16
|
+
@decode = DecodeConfiguration.new
|
17
|
+
@jwk = JwkConfiguration.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|