jwt 1.5.6 → 2.0.0
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/.ebert.yml +17 -0
- data/.reek.yml +40 -0
- data/.rubocop.yml +96 -0
- data/.travis.yml +9 -8
- data/CHANGELOG.md +82 -1
- data/Gemfile +0 -1
- data/README.md +71 -8
- data/lib/jwt/decode.rb +21 -29
- data/lib/jwt/default_options.rb +14 -0
- data/lib/jwt/encode.rb +51 -0
- data/lib/jwt/error.rb +2 -0
- data/lib/jwt/security_utils.rb +52 -0
- data/lib/jwt/signature.rb +106 -0
- data/lib/jwt/verify.rb +48 -53
- data/lib/jwt/version.rb +3 -3
- data/lib/jwt.rb +28 -159
- data/ruby-jwt.gemspec +4 -3
- data/spec/integration/readme_examples_spec.rb +20 -8
- data/spec/jwt/verify_spec.rb +64 -42
- data/spec/jwt_spec.rb +49 -32
- data/spec/spec_helper.rb +4 -7
- metadata +33 -15
- data/lib/jwt/json.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c63d3d103ec14f12ea2b51b95ae8f5407dd7ace9
|
4
|
+
data.tar.gz: f1de3f1e8ddfb79aa690a1f6d44492c70d037942
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b19fcd5018d17e4277a49abc5787cee37ff3991fc8cbcc97dbb00f50c3878fc08062d97e18e07cdaf5f8f2f09cfbf5a8937e11859ae9b44d90a8d5a20caa021
|
7
|
+
data.tar.gz: f9df1adefd0f0d4525567372c8283e72639b2ee67320a893ef03d470bbbd6afd09a65725d3eb3153f8c68e7d40f693c7da3a5ed138ab766a23aa6ebbfe5c62f6
|
data/.ebert.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
styleguide: plataformatec/linters
|
2
|
+
engines:
|
3
|
+
reek:
|
4
|
+
enabled: true
|
5
|
+
fixme:
|
6
|
+
enabled: true
|
7
|
+
rubocop:
|
8
|
+
enabled: true
|
9
|
+
duplication:
|
10
|
+
config:
|
11
|
+
languages:
|
12
|
+
- ruby
|
13
|
+
enabled: true
|
14
|
+
remark-lint:
|
15
|
+
enabled: true
|
16
|
+
exclude_paths:
|
17
|
+
- spec
|
data/.reek.yml
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
---
|
2
|
+
TooManyStatements:
|
3
|
+
max_statements: 10
|
4
|
+
UncommunicativeMethodName:
|
5
|
+
reject:
|
6
|
+
- !ruby/regexp /^[a-z]$/
|
7
|
+
- !ruby/regexp /[0-9]$/
|
8
|
+
UncommunicativeParameterName:
|
9
|
+
reject:
|
10
|
+
- !ruby/regexp /^.$/
|
11
|
+
- !ruby/regexp /[0-9]$/
|
12
|
+
- !ruby/regexp /^_/
|
13
|
+
UncommunicativeVariableName:
|
14
|
+
reject:
|
15
|
+
- !ruby/regexp /^.$/
|
16
|
+
- !ruby/regexp /[0-9]$/
|
17
|
+
UtilityFunction:
|
18
|
+
enabled: false
|
19
|
+
LongParameterList:
|
20
|
+
enabled: false
|
21
|
+
DuplicateMethodCall:
|
22
|
+
max_calls: 2
|
23
|
+
IrresponsibleModule:
|
24
|
+
enabled: false
|
25
|
+
NestedIterators:
|
26
|
+
max_allowed_nesting: 2
|
27
|
+
PrimaDonnaMethod:
|
28
|
+
enabled: false
|
29
|
+
UnusedParameters:
|
30
|
+
enabled: false
|
31
|
+
FeatureEnvy:
|
32
|
+
enabled: false
|
33
|
+
ControlParameter:
|
34
|
+
enabled: false
|
35
|
+
UnusedPrivateMethod:
|
36
|
+
enabled: false
|
37
|
+
InstanceVariableAssumption:
|
38
|
+
exclude:
|
39
|
+
- !ruby/regexp /Controller$/
|
40
|
+
- !ruby/regexp /Mailer$/s
|
data/.rubocop.yml
CHANGED
@@ -1,2 +1,98 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'bin/**/*'
|
4
|
+
- 'db/**/*'
|
5
|
+
- 'config/**/*'
|
6
|
+
- 'script/**/*'
|
7
|
+
|
8
|
+
Rails:
|
9
|
+
Enabled: true
|
10
|
+
|
11
|
+
Style/AlignParameters:
|
12
|
+
EnforcedStyle: with_fixed_indentation
|
13
|
+
|
14
|
+
Style/CaseIndentation:
|
15
|
+
EnforcedStyle: end
|
16
|
+
|
17
|
+
Style/AsciiComments:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Style/IndentHash:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/CollectionMethods:
|
24
|
+
Enabled: true
|
25
|
+
PreferredMethods:
|
26
|
+
inject: 'inject'
|
27
|
+
|
28
|
+
Style/Documentation:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Style/BlockDelimiters:
|
32
|
+
Exclude:
|
33
|
+
- spec/**/*_spec.rb
|
34
|
+
|
35
|
+
Style/BracesAroundHashParameters:
|
36
|
+
Exclude:
|
37
|
+
- spec/**/*_spec.rb
|
38
|
+
|
39
|
+
Style/GuardClause:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
Style/IfUnlessModifier:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Style/SpaceInsideHashLiteralBraces:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Style/Lambda:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
Style/RaiseArgs:
|
52
|
+
Enabled: false
|
53
|
+
|
54
|
+
Style/SignalException:
|
55
|
+
Enabled: false
|
56
|
+
|
57
|
+
Metrics/AbcSize:
|
58
|
+
Max: 20
|
59
|
+
|
60
|
+
Metrics/ClassLength:
|
61
|
+
Max: 100
|
62
|
+
|
63
|
+
Metrics/ModuleLength:
|
64
|
+
Max: 100
|
65
|
+
|
1
66
|
Metrics/LineLength:
|
2
67
|
Enabled: false
|
68
|
+
|
69
|
+
Metrics/MethodLength:
|
70
|
+
Max: 15
|
71
|
+
|
72
|
+
Style/SingleLineBlockParams:
|
73
|
+
Enabled: false
|
74
|
+
|
75
|
+
Lint/EndAlignment:
|
76
|
+
EnforcedStyleAlignWith: variable
|
77
|
+
|
78
|
+
Style/FormatString:
|
79
|
+
Enabled: false
|
80
|
+
|
81
|
+
Style/MultilineMethodCallIndentation:
|
82
|
+
EnforcedStyle: indented
|
83
|
+
|
84
|
+
Style/MultilineOperationIndentation:
|
85
|
+
EnforcedStyle: indented
|
86
|
+
|
87
|
+
Style/WordArray:
|
88
|
+
Enabled: false
|
89
|
+
|
90
|
+
Style/RedundantSelf:
|
91
|
+
Enabled: false
|
92
|
+
|
93
|
+
Style/AlignHash:
|
94
|
+
Enabled: true
|
95
|
+
EnforcedLastArgumentHashStyle: always_ignore
|
96
|
+
|
97
|
+
Style/TrivialAccessors:
|
98
|
+
AllowPredicates: true
|
data/.travis.yml
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
-
sudo:
|
1
|
+
sudo: required
|
2
2
|
cache: bundler
|
3
|
+
dist: trusty
|
3
4
|
language: ruby
|
4
5
|
rvm:
|
5
|
-
- 1.9.3
|
6
|
-
- 2.0.0
|
7
|
-
- 2.1.0
|
8
6
|
- 2.2.0
|
9
7
|
- 2.3.0
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
- 2.4.0
|
9
|
+
script: "bundle exec rspec && bundle exec codeclimate-test-reporter"
|
10
|
+
before_install:
|
11
|
+
- sudo add-apt-repository ppa:chris-lea/libsodium -y
|
12
|
+
- sudo apt-get update -q
|
13
|
+
- sudo apt-get install libsodium-dev -y
|
14
|
+
- gem install bundler
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,86 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v2.0.0](https://github.com/jwt/ruby-jwt/tree/v2.0.0) (2017-09-03)
|
4
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.0.0.beta1...v2.0.0)
|
5
|
+
|
6
|
+
**Fixed bugs:**
|
7
|
+
|
8
|
+
- Support versions outside 2.1 [\#209](https://github.com/jwt/ruby-jwt/issues/209)
|
9
|
+
- Verifying expiration without leeway throws exception [\#206](https://github.com/jwt/ruby-jwt/issues/206)
|
10
|
+
- Ruby interpreter warning [\#200](https://github.com/jwt/ruby-jwt/issues/200)
|
11
|
+
- TypeError: no implicit conversion of String into Integer [\#188](https://github.com/jwt/ruby-jwt/issues/188)
|
12
|
+
- Fix JWT.encode\(nil\) [\#203](https://github.com/jwt/ruby-jwt/pull/203) ([tmm1](https://github.com/tmm1))
|
13
|
+
|
14
|
+
**Closed issues:**
|
15
|
+
|
16
|
+
- Possibility to disable claim verifications [\#222](https://github.com/jwt/ruby-jwt/issues/222)
|
17
|
+
- Proper way to verify Firebase id tokens [\#216](https://github.com/jwt/ruby-jwt/issues/216)
|
18
|
+
|
19
|
+
**Merged pull requests:**
|
20
|
+
|
21
|
+
- Skip 'exp' claim validation for array payloads [\#224](https://github.com/jwt/ruby-jwt/pull/224) ([excpt](https://github.com/excpt))
|
22
|
+
- Use a default leeway of 0 [\#223](https://github.com/jwt/ruby-jwt/pull/223) ([travisofthenorth](https://github.com/travisofthenorth))
|
23
|
+
- Fix reported codesmells [\#221](https://github.com/jwt/ruby-jwt/pull/221) ([excpt](https://github.com/excpt))
|
24
|
+
- Add fancy gem version badge [\#220](https://github.com/jwt/ruby-jwt/pull/220) ([excpt](https://github.com/excpt))
|
25
|
+
- Add missing dist option to .travis.yml [\#219](https://github.com/jwt/ruby-jwt/pull/219) ([excpt](https://github.com/excpt))
|
26
|
+
- Fix ruby version requirements in gemspec file [\#218](https://github.com/jwt/ruby-jwt/pull/218) ([excpt](https://github.com/excpt))
|
27
|
+
- Fix a little typo in the readme [\#214](https://github.com/jwt/ruby-jwt/pull/214) ([RyanBrushett](https://github.com/RyanBrushett))
|
28
|
+
- Update README.md [\#212](https://github.com/jwt/ruby-jwt/pull/212) ([zuzannast](https://github.com/zuzannast))
|
29
|
+
- Fix typo in HS512256 algorithm description [\#211](https://github.com/jwt/ruby-jwt/pull/211) ([ojab](https://github.com/ojab))
|
30
|
+
- Allow configuration of multiple acceptable issuers [\#210](https://github.com/jwt/ruby-jwt/pull/210) ([ojab](https://github.com/ojab))
|
31
|
+
- Enforce `exp` to be an `Integer` [\#205](https://github.com/jwt/ruby-jwt/pull/205) ([lucasmazza](https://github.com/lucasmazza))
|
32
|
+
- ruby 1.9.3 support message upd [\#204](https://github.com/jwt/ruby-jwt/pull/204) ([maokomioko](https://github.com/maokomioko))
|
33
|
+
- Guard against partially loaded RbNaCl when failing to load libsodium [\#202](https://github.com/jwt/ruby-jwt/pull/202) ([Dorian](https://github.com/Dorian))
|
34
|
+
|
35
|
+
## [v2.0.0.beta1](https://github.com/jwt/ruby-jwt/tree/v2.0.0.beta1) (2017-02-27)
|
36
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.6...v2.0.0.beta1)
|
37
|
+
|
38
|
+
**Implemented enhancements:**
|
39
|
+
|
40
|
+
- Error with method sign for String [\#171](https://github.com/jwt/ruby-jwt/issues/171)
|
41
|
+
- Refactor the encondig code [\#121](https://github.com/jwt/ruby-jwt/issues/121)
|
42
|
+
- Refactor [\#196](https://github.com/jwt/ruby-jwt/pull/196) ([EmilioCristalli](https://github.com/EmilioCristalli))
|
43
|
+
- Move signature logic to its own module [\#195](https://github.com/jwt/ruby-jwt/pull/195) ([EmilioCristalli](https://github.com/EmilioCristalli))
|
44
|
+
- Add options for claim-specific leeway [\#187](https://github.com/jwt/ruby-jwt/pull/187) ([EmilioCristalli](https://github.com/EmilioCristalli))
|
45
|
+
- Add user friendly encode error if private key is a String, \#171 [\#176](https://github.com/jwt/ruby-jwt/pull/176) ([xamenrax](https://github.com/xamenrax))
|
46
|
+
- Return empty string if signature less than byte\_size \#155 [\#175](https://github.com/jwt/ruby-jwt/pull/175) ([xamenrax](https://github.com/xamenrax))
|
47
|
+
- Remove 'typ' optional parameter [\#174](https://github.com/jwt/ruby-jwt/pull/174) ([xamenrax](https://github.com/xamenrax))
|
48
|
+
- Pass payload to keyfinder [\#172](https://github.com/jwt/ruby-jwt/pull/172) ([CodeMonkeySteve](https://github.com/CodeMonkeySteve))
|
49
|
+
- Use RbNaCl for HMAC if available with fallback to OpenSSL [\#149](https://github.com/jwt/ruby-jwt/pull/149) ([mwpastore](https://github.com/mwpastore))
|
50
|
+
|
51
|
+
**Fixed bugs:**
|
52
|
+
|
53
|
+
- ruby-jwt::raw\_to\_asn1: Fails for signatures less than byte\_size [\#155](https://github.com/jwt/ruby-jwt/issues/155)
|
54
|
+
- The leeway parameter is applies to all time based verifications [\#129](https://github.com/jwt/ruby-jwt/issues/129)
|
55
|
+
- Add options for claim-specific leeway [\#187](https://github.com/jwt/ruby-jwt/pull/187) ([EmilioCristalli](https://github.com/EmilioCristalli))
|
56
|
+
- Make algorithm option required to verify signature [\#184](https://github.com/jwt/ruby-jwt/pull/184) ([EmilioCristalli](https://github.com/EmilioCristalli))
|
57
|
+
- Validate audience when payload is a scalar and options is an array [\#183](https://github.com/jwt/ruby-jwt/pull/183) ([steti](https://github.com/steti))
|
58
|
+
|
59
|
+
**Closed issues:**
|
60
|
+
|
61
|
+
- Different encoded value between servers with same password [\#197](https://github.com/jwt/ruby-jwt/issues/197)
|
62
|
+
- Signature is different at each run [\#190](https://github.com/jwt/ruby-jwt/issues/190)
|
63
|
+
- Include custom headers with password [\#189](https://github.com/jwt/ruby-jwt/issues/189)
|
64
|
+
- can't create token - 'NotImplementedError: Unsupported signing method' [\#186](https://github.com/jwt/ruby-jwt/issues/186)
|
65
|
+
- Why jwt depends on json \< 2.0 ? [\#179](https://github.com/jwt/ruby-jwt/issues/179)
|
66
|
+
- Cannot verify JWT at all?? [\#177](https://github.com/jwt/ruby-jwt/issues/177)
|
67
|
+
- verify\_iss: true is raising JWT::DecodeError instead of JWT::InvalidIssuerError [\#170](https://github.com/jwt/ruby-jwt/issues/170)
|
68
|
+
|
69
|
+
**Merged pull requests:**
|
70
|
+
|
71
|
+
- Version bump 2.0.0.beta1 [\#199](https://github.com/jwt/ruby-jwt/pull/199) ([excpt](https://github.com/excpt))
|
72
|
+
- Update CHANGELOG.md and minor fixes [\#198](https://github.com/jwt/ruby-jwt/pull/198) ([excpt](https://github.com/excpt))
|
73
|
+
- Add Codacy coverage reporter [\#194](https://github.com/jwt/ruby-jwt/pull/194) ([excpt](https://github.com/excpt))
|
74
|
+
- Add minimum required ruby version to gemspec [\#193](https://github.com/jwt/ruby-jwt/pull/193) ([excpt](https://github.com/excpt))
|
75
|
+
- Code smell fixes [\#192](https://github.com/jwt/ruby-jwt/pull/192) ([excpt](https://github.com/excpt))
|
76
|
+
- Version bump to 2.0.0.dev [\#191](https://github.com/jwt/ruby-jwt/pull/191) ([excpt](https://github.com/excpt))
|
77
|
+
- Basic encode module refactoring \#121 [\#182](https://github.com/jwt/ruby-jwt/pull/182) ([xamenrax](https://github.com/xamenrax))
|
78
|
+
- Fix travis ci build configuration [\#181](https://github.com/jwt/ruby-jwt/pull/181) ([excpt](https://github.com/excpt))
|
79
|
+
- Fix travis ci build configuration [\#180](https://github.com/jwt/ruby-jwt/pull/180) ([excpt](https://github.com/excpt))
|
80
|
+
- Fix typo in README [\#178](https://github.com/jwt/ruby-jwt/pull/178) ([tomeduarte](https://github.com/tomeduarte))
|
81
|
+
- Fix code style [\#173](https://github.com/jwt/ruby-jwt/pull/173) ([excpt](https://github.com/excpt))
|
82
|
+
- Fixed a typo in a spec name [\#169](https://github.com/jwt/ruby-jwt/pull/169) ([Mingan](https://github.com/Mingan))
|
83
|
+
|
3
84
|
## [v1.5.6](https://github.com/jwt/ruby-jwt/tree/v1.5.6) (2016-09-19)
|
4
85
|
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.5...v1.5.6)
|
5
86
|
|
@@ -9,6 +90,7 @@
|
|
9
90
|
|
10
91
|
**Merged pull requests:**
|
11
92
|
|
93
|
+
- Update changelog [\#168](https://github.com/jwt/ruby-jwt/pull/168) ([excpt](https://github.com/excpt))
|
12
94
|
- Fix rubocop code smells [\#167](https://github.com/jwt/ruby-jwt/pull/167) ([excpt](https://github.com/excpt))
|
13
95
|
|
14
96
|
## [v1.5.5](https://github.com/jwt/ruby-jwt/tree/v1.5.5) (2016-09-16)
|
@@ -253,7 +335,6 @@
|
|
253
335
|
|
254
336
|
**Closed issues:**
|
255
337
|
|
256
|
-
- yanking of version 0.1.12 causes issues [\#39](https://github.com/jwt/ruby-jwt/issues/39)
|
257
338
|
- Semantic versioning [\#37](https://github.com/jwt/ruby-jwt/issues/37)
|
258
339
|
- Update gem to get latest changes [\#36](https://github.com/jwt/ruby-jwt/issues/36)
|
259
340
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# JWT
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/jwt)
|
3
4
|
[](https://travis-ci.org/jwt/ruby-jwt)
|
4
5
|
[](https://codeclimate.com/github/jwt/ruby-jwt)
|
5
6
|
[](https://codeclimate.com/github/jwt/ruby-jwt/coverage)
|
@@ -7,11 +8,11 @@
|
|
7
8
|
|
8
9
|
A pure ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) standard.
|
9
10
|
|
10
|
-
If you have further questions
|
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).
|
11
12
|
|
12
13
|
## Announcements
|
13
14
|
|
14
|
-
* Ruby 1.9.3 support
|
15
|
+
* Ruby 1.9.3 support was dropped at December 31st, 2016.
|
15
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)
|
16
17
|
|
17
18
|
## Installing
|
@@ -55,7 +56,7 @@ decoded_token = JWT.decode token, nil, false
|
|
55
56
|
# Array
|
56
57
|
# [
|
57
58
|
# {"data"=>"test"}, # payload
|
58
|
-
# {"
|
59
|
+
# {"alg"=>"none"} # header
|
59
60
|
# ]
|
60
61
|
puts decoded_token
|
61
62
|
```
|
@@ -63,6 +64,7 @@ puts decoded_token
|
|
63
64
|
**HMAC** (default: HS256)
|
64
65
|
|
65
66
|
* HS256 - HMAC using SHA-256 hash algorithm (default)
|
67
|
+
* HS512256 - HMAC using SHA-512-256 hash algorithm (only available with RbNaCl; see note below)
|
66
68
|
* HS384 - HMAC using SHA-384 hash algorithm
|
67
69
|
* HS512 - HMAC using SHA-512 hash algorithm
|
68
70
|
|
@@ -79,11 +81,17 @@ decoded_token = JWT.decode token, hmac_secret, true, { :algorithm => 'HS256' }
|
|
79
81
|
# Array
|
80
82
|
# [
|
81
83
|
# {"data"=>"test"}, # payload
|
82
|
-
# {"
|
84
|
+
# {"alg"=>"HS256"} # header
|
83
85
|
# ]
|
84
86
|
puts decoded_token
|
85
87
|
```
|
86
88
|
|
89
|
+
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.
|
90
|
+
|
91
|
+
[RbNaCl](https://github.com/cryptosphere/rbnacl) requires
|
92
|
+
[libsodium](https://github.com/jedisct1/libsodium), it can be installed
|
93
|
+
on MacOS with `brew install libsodium`.
|
94
|
+
|
87
95
|
**RSA**
|
88
96
|
|
89
97
|
* RS256 - RSA using SHA-256 hash algorithm
|
@@ -104,7 +112,7 @@ decoded_token = JWT.decode token, rsa_public, true, { :algorithm => 'RS256' }
|
|
104
112
|
# Array
|
105
113
|
# [
|
106
114
|
# {"data"=>"test"}, # payload
|
107
|
-
# {"
|
115
|
+
# {"alg"=>"RS256"} # header
|
108
116
|
# ]
|
109
117
|
puts decoded_token
|
110
118
|
```
|
@@ -131,7 +139,7 @@ decoded_token = JWT.decode token, ecdsa_public, true, { :algorithm => 'ES256' }
|
|
131
139
|
# Array
|
132
140
|
# [
|
133
141
|
# {"test"=>"data"}, # payload
|
134
|
-
# {"
|
142
|
+
# {"alg"=>"ES256"} # header
|
135
143
|
# ]
|
136
144
|
puts decoded_token
|
137
145
|
```
|
@@ -152,6 +160,38 @@ used. JWT supports these reserved claim names:
|
|
152
160
|
- 'iat' (Issued At) Claim
|
153
161
|
- 'sub' (Subject) Claim
|
154
162
|
|
163
|
+
## Add custom header fields
|
164
|
+
Ruby-jwt gem supports custom [header fields] (https://tools.ietf.org/html/rfc7519#section-5)
|
165
|
+
To add custom header fields you need to pass `header_fields` parameter
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
token = JWT.encode payload, key, algorithm='HS256', header_fields={}
|
169
|
+
```
|
170
|
+
|
171
|
+
**Example:**
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
require 'jwt'
|
175
|
+
|
176
|
+
payload = {:data => 'test'}
|
177
|
+
|
178
|
+
# IMPORTANT: set nil as password parameter
|
179
|
+
token = JWT.encode payload, nil, 'none', { :typ => "JWT" }
|
180
|
+
|
181
|
+
# eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.
|
182
|
+
puts token
|
183
|
+
|
184
|
+
# Set password to nil and validation to false otherwise this won't work
|
185
|
+
decoded_token = JWT.decode token, nil, false
|
186
|
+
|
187
|
+
# Array
|
188
|
+
# [
|
189
|
+
# {"data"=>"test"}, # payload
|
190
|
+
# {"typ"=>"JWT", "alg"=>"none"} # header
|
191
|
+
# ]
|
192
|
+
puts decoded_token
|
193
|
+
```
|
194
|
+
|
155
195
|
### Expiration Time Claim
|
156
196
|
|
157
197
|
From [Oauth JSON Web Token 4.1.4. "exp" (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4):
|
@@ -186,7 +226,7 @@ token = JWT.encode exp_payload, hmac_secret, 'HS256'
|
|
186
226
|
|
187
227
|
begin
|
188
228
|
# add leeway to ensure the token is still accepted
|
189
|
-
decoded_token = JWT.decode token, hmac_secret, true, { :
|
229
|
+
decoded_token = JWT.decode token, hmac_secret, true, { :exp_leeway => leeway, :algorithm => 'HS256' }
|
190
230
|
rescue JWT::ExpiredSignature
|
191
231
|
# Handle expired token, e.g. logout user or deny access
|
192
232
|
end
|
@@ -226,7 +266,7 @@ token = JWT.encode nbf_payload, hmac_secret, 'HS256'
|
|
226
266
|
|
227
267
|
begin
|
228
268
|
# add leeway to ensure the token is valid
|
229
|
-
decoded_token = JWT.decode token, hmac_secret, true, { :
|
269
|
+
decoded_token = JWT.decode token, hmac_secret, true, { :nbf_leeway => leeway, :algorithm => 'HS256' }
|
230
270
|
rescue JWT::ImmatureSignature
|
231
271
|
# Handle invalid token, e.g. logout user or deny access
|
232
272
|
end
|
@@ -238,6 +278,8 @@ From [Oauth JSON Web Token 4.1.1. "iss" (Issuer) Claim](https://tools.ietf.org/h
|
|
238
278
|
|
239
279
|
> The `iss` (issuer) claim identifies the principal that issued the JWT. The processing of this claim is generally application specific. The `iss` value is a case-sensitive string containing a ***StringOrURI*** value. Use of this claim is OPTIONAL.
|
240
280
|
|
281
|
+
You can pass multiple allowed issuers as an Array, verification will pass if one of them matches the `iss` value in the payload.
|
282
|
+
|
241
283
|
```ruby
|
242
284
|
iss = 'My Awesome Company Inc. or https://my.awesome.website/'
|
243
285
|
iss_payload = { :data => 'data', :iss => iss }
|
@@ -305,6 +347,8 @@ From [Oauth JSON Web Token 4.1.6. "iat" (Issued At) Claim](https://tools.ietf.or
|
|
305
347
|
|
306
348
|
> The `iat` (issued at) claim identifies the time at which the JWT was issued. This claim can be used to determine the age of the JWT. Its value MUST be a number containing a ***NumericDate*** value. Use of this claim is OPTIONAL.
|
307
349
|
|
350
|
+
**Handle Issued At Claim**
|
351
|
+
|
308
352
|
```ruby
|
309
353
|
iat = Time.now.to_i
|
310
354
|
iat_payload = { :data => 'data', :iat => iat }
|
@@ -319,6 +363,25 @@ rescue JWT::InvalidIatError
|
|
319
363
|
end
|
320
364
|
```
|
321
365
|
|
366
|
+
**Adding Leeway**
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
iat = Time.now.to_i + 10
|
370
|
+
leeway = 30 # seconds
|
371
|
+
|
372
|
+
iat_payload = { :data => 'data', :iat => iat }
|
373
|
+
|
374
|
+
# build token issued in the future
|
375
|
+
token = JWT.encode iat_payload, hmac_secret, 'HS256'
|
376
|
+
|
377
|
+
begin
|
378
|
+
# add leeway to ensure the token is accepted
|
379
|
+
decoded_token = JWT.decode token, hmac_secret, true, { :iat_leeway => leeway, :verify_iat => true, :algorithm => 'HS256' }
|
380
|
+
rescue JWT::InvalidIatError
|
381
|
+
# Handle invalid token, e.g. logout user or deny access
|
382
|
+
end
|
383
|
+
```
|
384
|
+
|
322
385
|
### Subject Claim
|
323
386
|
|
324
387
|
From [Oauth JSON Web Token 4.1.2. "sub" (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2):
|
data/lib/jwt/decode.rb
CHANGED
@@ -1,57 +1,49 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require '
|
2
|
+
|
3
|
+
require 'json'
|
4
4
|
|
5
5
|
# JWT::Decode module
|
6
6
|
module JWT
|
7
|
-
extend JWT::Json
|
8
|
-
|
9
7
|
# Decoding logic for JWT
|
10
8
|
class Decode
|
11
9
|
attr_reader :header, :payload, :signature
|
12
10
|
|
13
|
-
def
|
11
|
+
def self.base64url_decode(str)
|
12
|
+
str += '=' * (4 - str.length.modulo(4))
|
13
|
+
Base64.decode64(str.tr('-_', '+/'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(jwt, verify)
|
14
17
|
@jwt = jwt
|
15
|
-
@key = key
|
16
18
|
@verify = verify
|
17
|
-
@
|
18
|
-
@
|
19
|
+
@header = ''
|
20
|
+
@payload = ''
|
21
|
+
@signature = ''
|
19
22
|
end
|
20
23
|
|
21
24
|
def decode_segments
|
22
|
-
header_segment, payload_segment, crypto_segment = raw_segments
|
25
|
+
header_segment, payload_segment, crypto_segment = raw_segments
|
23
26
|
@header, @payload = decode_header_and_payload(header_segment, payload_segment)
|
24
27
|
@signature = Decode.base64url_decode(crypto_segment.to_s) if @verify
|
25
28
|
signing_input = [header_segment, payload_segment].join('.')
|
26
29
|
[@header, @payload, @signature, signing_input]
|
27
30
|
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
private
|
33
|
+
|
34
|
+
def raw_segments
|
35
|
+
segments = @jwt.split('.')
|
36
|
+
required_num_segments = @verify ? [3] : [2, 3]
|
32
37
|
raise(JWT::DecodeError, 'Not enough or too many segments') unless required_num_segments.include? segments.length
|
33
38
|
segments
|
34
39
|
end
|
35
|
-
private :raw_segments
|
36
40
|
|
37
41
|
def decode_header_and_payload(header_segment, payload_segment)
|
38
|
-
header =
|
39
|
-
payload =
|
42
|
+
header = JSON.parse(Decode.base64url_decode(header_segment))
|
43
|
+
payload = JSON.parse(Decode.base64url_decode(payload_segment))
|
40
44
|
[header, payload]
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
def self.base64url_decode(str)
|
45
|
-
str += '=' * (4 - str.length.modulo(4))
|
46
|
-
Base64.decode64(str.tr('-_', '+/'))
|
47
|
-
end
|
48
|
-
|
49
|
-
def verify
|
50
|
-
@options.each do |key, val|
|
51
|
-
next unless key.to_s =~ /verify/
|
52
|
-
|
53
|
-
Verify.send(key, payload, @options) if val
|
54
|
-
end
|
45
|
+
rescue JSON::ParserError
|
46
|
+
raise JWT::DecodeError, 'Invalid segment encoding'
|
55
47
|
end
|
56
48
|
end
|
57
49
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module JWT
|
2
|
+
module DefaultOptions
|
3
|
+
DEFAULT_OPTIONS = {
|
4
|
+
verify_expiration: true,
|
5
|
+
verify_not_before: true,
|
6
|
+
verify_iss: false,
|
7
|
+
verify_iat: false,
|
8
|
+
verify_jti: false,
|
9
|
+
verify_aud: false,
|
10
|
+
verify_sub: false,
|
11
|
+
leeway: 0
|
12
|
+
}.freeze
|
13
|
+
end
|
14
|
+
end
|
data/lib/jwt/encode.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
# JWT::Encode module
|
6
|
+
module JWT
|
7
|
+
# Encoding logic for JWT
|
8
|
+
class Encode
|
9
|
+
attr_reader :payload, :key, :algorithm, :header_fields, :segments
|
10
|
+
|
11
|
+
def self.base64url_encode(str)
|
12
|
+
Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '')
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(payload, key, algorithm, header_fields)
|
16
|
+
@payload = payload
|
17
|
+
@key = key
|
18
|
+
@algorithm = algorithm
|
19
|
+
@header_fields = header_fields
|
20
|
+
@segments = encode_segments
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def encoded_header
|
26
|
+
header = { 'alg' => @algorithm }.merge(@header_fields)
|
27
|
+
Encode.base64url_encode(JSON.generate(header))
|
28
|
+
end
|
29
|
+
|
30
|
+
def encoded_payload
|
31
|
+
raise InvalidPayload, 'exp claim must be an integer' if @payload && !@payload.is_a?(Array) && @payload.key?('exp') && !@payload['exp'].is_a?(Integer)
|
32
|
+
Encode.base64url_encode(JSON.generate(@payload))
|
33
|
+
end
|
34
|
+
|
35
|
+
def encoded_signature(signing_input)
|
36
|
+
if @algorithm == 'none'
|
37
|
+
''
|
38
|
+
else
|
39
|
+
signature = JWT::Signature.sign(@algorithm, signing_input, @key)
|
40
|
+
Encode.base64url_encode(signature)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def encode_segments
|
45
|
+
header = encoded_header
|
46
|
+
payload = encoded_payload
|
47
|
+
signature = encoded_signature([header, payload].join('.'))
|
48
|
+
[header, payload, signature].join('.')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|